Railway Operation Simulator  v2.9.2
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
241 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
242 {
243  if(lower.second < higher.second)
244  {
245  return(true);
246  }
247  else if(lower.second > higher.second)
248  {
249  return(false);
250  }
251  else if(lower.second == higher.second)
252  {
253  if(lower.first < higher.first)
254  {
255  return(true);
256  }
257  }
258  return(false);
259 }
260 
261 // ---------------------------------------------------------------------------
262 // PrefDirElement Functions
263 // ---------------------------------------------------------------------------
264 
265 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
266  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
267  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
268 {
269  if(!EntryExitNumber())
270  {
271  throw Exception("EXNumber failure in TPrefDirElement constructor");
272  }
275 }
276 
277 // ---------------------------------------------------------------------------
278 
279 AnsiString TPrefDirElement::LogPrefDir() const
280 // for debugging when passed as a call parameter
281 {
282  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
283  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
284  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
285  AnsiString(TrainIDOnBridgeTrackPos23);
286 
287 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
288  return(LogString);
289 }
290 
291 // ---------------------------------------------------------------------------
292 
293 bool TPrefDirElement::EntryExitNumber() // true for valid number
294 /*
295  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
296  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
297  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
298  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
299  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
300  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
301  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
302  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
303  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
304 */
305 
306 {
307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
308  int EXArray[16][2] =
309  {{4, 6}, {2, 8}, // horizontal & vertical
310  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
311  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
312  {1, 9}, {3, 7}}; // forward & reverse diagonals
313 
314  int EXNum = -1;
315  int Entry, Exit;
316 
317  if(ELink > -1)
318  {
319  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
320  }
321  else if(Link[2] == -1)
322  {
323  Entry = Link[0];
324  }
325  else
326  {
327  Utilities->CallLogPop(122);
328  return(false);
329  }
330  if(XLink > -1)
331  {
332  Exit = XLink;
333  }
334  else if(Link[2] == -1)
335  {
336  Exit = Link[1];
337  }
338  else
339  {
340  Utilities->CallLogPop(123);
341  return(false);
342  }
343  for(int x = 0; x < 16; x++)
344  {
345  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
346  {
347  EXNum = x;
348  }
349  }
350  if(EXNum == -1)
351  {
352  Utilities->CallLogPop(124);
353  return(false);
354  }
355  int BrNum = -1;
356 
357 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
358  the graphic for each of which is different because of the shape of the overbridge. The basic
359  entry/exit value is computed above, and this used to select only from elements with that entry/exit
360  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
361  int BrEXArray[24][2] = {
362  {4,6},{2,8},{1,9},{3,7},
363  {1,9},{3,7},{1,9},{3,7},
364  {2,8},{4,6},{2,8},{4,6}
365 */
366 
367  if(TrackType == Bridge)
368  {
369  if(EXNum == 1)
370  {
371  if(SpeedTag == 49)
372  {
373  BrNum = 1 + 16;
374  }
375  else if(SpeedTag == 54)
376  {
377  BrNum = 8 + 16;
378  }
379  else if(SpeedTag == 55)
380  {
381  BrNum = 10 + 16;
382  }
383  }
384  else if(EXNum == 0)
385  {
386  if(SpeedTag == 48)
387  {
388  BrNum = 0 + 16;
389  }
390  else if(SpeedTag == 58)
391  {
392  BrNum = 11 + 16;
393  }
394  else if(SpeedTag == 59)
395  {
396  BrNum = 9 + 16;
397  }
398  }
399  else if(EXNum == 14)
400  {
401  if(SpeedTag == 50)
402  {
403  BrNum = 2 + 16;
404  }
405  else if(SpeedTag == 52)
406  {
407  BrNum = 4 + 16;
408  }
409  else if(SpeedTag == 57)
410  {
411  BrNum = 6 + 16;
412  }
413  }
414  else if(EXNum == 15)
415  {
416  if(SpeedTag == 51)
417  {
418  BrNum = 3 + 16;
419  }
420  else if(SpeedTag == 53)
421  {
422  BrNum = 7 + 16;
423  }
424  else if(SpeedTag == 56)
425  {
426  BrNum = 5 + 16;
427  }
428  }
429  }
430  if(BrNum == -1)
431  {
432  EXNumber = EXNum;
433  }
434  else
435  {
436  EXNumber = BrNum;
437  }
438  Utilities->CallLogPop(125);
439  return(true);
440 }
441 
442 // ---------------------------------------------------------------------------
443 
445 /*
446  This is the basic track graphic for use in plotting the original graphic during route flashing.
447  Enter with all set apart from EXGraphic & EntryDirectionGraphic
448 */
449 {
450  if(SpeedTag == 64)
451  {
452  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
453 
454  }
455  if(SpeedTag == 65)
456  {
457  return(RailGraphics->LinkGraphicsPtr[17]);
458  }
459  if(SpeedTag == 66)
460  {
461  return(RailGraphics->LinkGraphicsPtr[18]);
462  }
463  if(SpeedTag == 67)
464  {
465  return(RailGraphics->LinkGraphicsPtr[19]);
466  }
467  if(SpeedTag == 80)
468  {
469  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
470 
471  }
472  if(SpeedTag == 81)
473  {
474  return(RailGraphics->LinkGraphicsPtr[21]);
475  }
476  if(SpeedTag == 82)
477  {
478  return(RailGraphics->LinkGraphicsPtr[22]);
479  }
480  if(SpeedTag == 83)
481  {
482  return(RailGraphics->LinkGraphicsPtr[23]);
483  }
484  if(SpeedTag == 84)
485  {
486  return(RailGraphics->LinkGraphicsPtr[24]);
487  }
488  if(SpeedTag == 85)
489  {
490  return(RailGraphics->LinkGraphicsPtr[25]);
491  }
492  if(SpeedTag == 86)
493  {
494  return(RailGraphics->LinkGraphicsPtr[26]);
495  }
496  if(SpeedTag == 87)
497  {
498  return(RailGraphics->LinkGraphicsPtr[27]);
499  }
500  if(SpeedTag == 129)
501  {
502  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
503 
504  }
505  if(SpeedTag == 130)
506  {
507  return(RailGraphics->LinkGraphicsPtr[29]);
508  }
509  if(XLinkPos == -1) // not set, could be first element or last element = leading point
510  {
511 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
512 // Points & don't want to display these)
513  if(Link[2] != -1)
514  {
515  return(0); // i.e. complex element, don't display
516  }
517  else
518  {
519  if(!EntryExitNumber())
520  {
521  throw Exception("Error in EntryExitNumber 4");
522  }
523  else
524  {
526  }
527  }
528  }
529  if(EXNumber > 15) // underbridge
530  {
531  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
532  }
533  else
534  {
536  }
537 }
538 
539 // ---------------------------------------------------------------------------
540 
542 /*
543  As above but for PrefDir graphics.
544 */
545 {
546  if(SpeedTag == 64)
547  {
548  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
549 
550  }
551  if(SpeedTag == 65)
552  {
554  }
555  if(SpeedTag == 66)
556  {
558  }
559  if(SpeedTag == 67)
560  {
562  }
563  if(SpeedTag == 80)
564  {
565  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
566 
567  }
568  if(SpeedTag == 81)
569  {
571  }
572  if(SpeedTag == 82)
573  {
575  }
576  if(SpeedTag == 83)
577  {
579  }
580  if(SpeedTag == 84)
581  {
583  }
584  if(SpeedTag == 85)
585  {
587  }
588  if(SpeedTag == 86)
589  {
591  }
592  if(SpeedTag == 87)
593  {
595  }
596  if(SpeedTag == 129)
597  {
598  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
599 
600  }
601  if(SpeedTag == 130)
602  {
604  }
605  if(XLinkPos == -1) // not set, could be first element or last element = leading point
606  {
607 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
608  if(Link[2] != -1)
609  {
610  return(0); // i.e. complex element, don't display
611  }
612  else
613  {
614  if(!EntryExitNumber())
615  {
616  throw Exception("Error in EntryExitNumber 5");
617  }
618  else
619  {
621  }
622  }
623  }
624  if(EXNumber > 15) // underbridge
625  {
627  }
628  else
629  {
631  }
632 }
633 
634 // ---------------------------------------------------------------------------
635 
636 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
637 /*
638  As above but for route graphics.
639 */
640 {
641  if(!AutoSigsFlag && !PrefDirRoute)
642  {
643  if(SpeedTag == 64)
644  {
645  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
646 
647  }
648  if(SpeedTag == 65)
649  {
651  }
652  if(SpeedTag == 66)
653  {
655  }
656  if(SpeedTag == 67)
657  {
659  }
660  if(SpeedTag == 80)
661  {
662  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
663 
664  }
665  if(SpeedTag == 81)
666  {
668  }
669  if(SpeedTag == 82)
670  {
672  }
673  if(SpeedTag == 83)
674  {
676  }
677  if(SpeedTag == 84)
678  {
680  }
681  if(SpeedTag == 85)
682  {
684  }
685  if(SpeedTag == 86)
686  {
688  }
689  if(SpeedTag == 87)
690  {
692  }
693  if(SpeedTag == 129)
694  {
695  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
696 
697  }
698  if(SpeedTag == 130)
699  {
701  }
702  if(XLinkPos == -1) // not set, could be first element or last element = leading point
703  {
704  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
705  if(Link[2] != -1)
706  {
707  return(0); // i.e. complex element, don't display
708  }
709  else
710  {
711  if(!EntryExitNumber())
712  {
713  throw Exception("Error in EntryExitNumber 6");
714  }
715  else
716  {
718  }
719  }
720  }
721  if(EXNumber > 15) // underbridge
722  {
724  }
725  else
726  {
728  }
729  }
730 
731  else if(!AutoSigsFlag && PrefDirRoute)
732  {
733  if(SpeedTag == 64)
734  {
735  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
736 
737  }
738  if(SpeedTag == 65)
739  {
741  }
742  if(SpeedTag == 66)
743  {
745  }
746  if(SpeedTag == 67)
747  {
749  }
750  if(SpeedTag == 80)
751  {
752  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
753 
754  }
755  if(SpeedTag == 81)
756  {
758  }
759  if(SpeedTag == 82)
760  {
762  }
763  if(SpeedTag == 83)
764  {
766  }
767  if(SpeedTag == 84)
768  {
770  }
771  if(SpeedTag == 85)
772  {
774  }
775  if(SpeedTag == 86)
776  {
778  }
779  if(SpeedTag == 87)
780  {
782  }
783  if(SpeedTag == 129)
784  {
785  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
786 
787  }
788  if(SpeedTag == 130)
789  {
791  }
792  if(XLinkPos == -1) // not set, could be first element or last element = leading point
793  {
794  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
795  if(Link[2] != -1)
796  {
797  return(0); // i.e. complex element, don't display
798  }
799  else
800  {
801  if(!EntryExitNumber())
802  {
803  throw Exception("Error in EntryExitNumber 10");
804  }
805  else
806  {
808  }
809  }
810  }
811  if(EXNumber > 15) // underbridge
812  {
814  }
815  else
816  {
818  }
819  }
820 
821  else
822  {
823  if(SpeedTag == 64)
824  {
825  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
826 
827  }
828  if(SpeedTag == 65)
829  {
831  }
832  if(SpeedTag == 66)
833  {
835  }
836  if(SpeedTag == 67)
837  {
839  }
840  if(SpeedTag == 80)
841  {
842  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
843 
844  }
845  if(SpeedTag == 81)
846  {
848  }
849  if(SpeedTag == 82)
850  {
852  }
853  if(SpeedTag == 83)
854  {
856  }
857  if(SpeedTag == 84)
858  {
860  }
861  if(SpeedTag == 85)
862  {
864  }
865  if(SpeedTag == 86)
866  {
868  }
869  if(SpeedTag == 87)
870  {
872  }
873  if(SpeedTag == 129)
874  {
875  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
876 
877  }
878  if(SpeedTag == 130)
879  {
881  }
882  if(XLinkPos == -1) // not set, could be first element or last element = leading point
883  {
884  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
885  if(Link[2] != -1)
886  {
887  return(0); // i.e. complex element, don't display
888  }
889  else
890  {
891  if(!EntryExitNumber())
892  {
893  throw Exception("Error in EntryExitNumber 11");
894  }
895  else
896  {
898  }
899  }
900  }
901  if(EXNumber > 15) // underbridge
902  {
904  }
905  else
906  {
908  }
909  }
910 }
911 
912 // ---------------------------------------------------------------------------
913 
915 /*
916  As above but for route flashing graphics. (Disused - now combined with above)
917 */
918 {
919  if(SpeedTag == 64)
920  {
921  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
922 
923  }
924  if(SpeedTag == 65)
925  {
927  }
928  if(SpeedTag == 66)
929  {
931  }
932  if(SpeedTag == 67)
933  {
935  }
936  if(SpeedTag == 80)
937  {
938  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
939 
940  }
941  if(SpeedTag == 81)
942  {
944  }
945  if(SpeedTag == 82)
946  {
948  }
949  if(SpeedTag == 83)
950  {
952  }
953  if(SpeedTag == 84)
954  {
956  }
957  if(SpeedTag == 85)
958  {
960  }
961  if(SpeedTag == 86)
962  {
964  }
965  if(SpeedTag == 87)
966  {
968  }
969  if(SpeedTag == 129)
970  {
971  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
972 
973  }
974  if(SpeedTag == 130)
975  {
977  }
978  if(XLinkPos == -1) // not set, could be first element or last element = leading point
979  {
980 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
981  if(Link[2] != -1)
982  {
983  return(0); // i.e. complex element, don't display
984  }
985  else
986  {
987  if(!EntryExitNumber())
988  {
989  throw Exception("Error in EntryExitNumber 7");
990  }
991  else
992  {
994  }
995  }
996  }
997  if(EXNumber > 15) // underbridge
998  {
1000  }
1001  else
1002  {
1004  }
1005 }
1006 
1007 // ---------------------------------------------------------------------------
1008 
1010 /*
1011  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1012 */
1013 {
1014  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1015  {
1017  }
1018  else
1019  {
1020  throw Exception("Error in EntryExitNumber 8");
1021  }
1022 }
1023 
1024 // ---------------------------------------------------------------------------
1025 
1026 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1027 /*
1028  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1029 */
1030 {
1031  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1032  {
1033  if(!AutoSigsFlag && !PrefDirRoute)
1034  {
1036  }
1037  else if(!AutoSigsFlag && PrefDirRoute)
1038  {
1040  }
1041  else
1042  {
1044  }
1045  }
1046  else
1047  {
1048  throw Exception("Error in EntryExitNumber 9");
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 
1055 /*
1056  Set == operator when TrackVectorPosition, ELink & XLink all same
1057 */
1058 {
1059  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1060  {
1061  return(true);
1062  }
1063  else
1064  {
1065  return(false);
1066  }
1067 }
1068 
1069 // ---------------------------------------------------------------------------
1070 
1072 /*
1073  Set != operator when any of TrackVectorPosition, ELink or XLink different
1074 */
1075 {
1076  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1077  {
1078  return(false);
1079  }
1080  else
1081  {
1082  return(true);
1083  }
1084 }
1085 
1086 // ---------------------------------------------------------------------------
1087 // Track functions
1088 // ---------------------------------------------------------------------------
1089 
1090 // ---------------------------------------------------------------------------
1091 
1092 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1093 {
1094  TypeOfRoute = 0;
1095  ReducedTimePenalty = false;
1096  BarrierState = Up;
1097  ChangeDuration = 0.0;
1098  BaseElementSpeedTag = 1;
1099  HLoc = 0;
1100  VLoc = 0;
1101  StartTime = TDateTime(0);
1102 }
1103 
1104 // ---------------------------------------------------------------------------
1105 
1107 {
1108 // CurrentSpeedButtonTag = 0; //not assigned yet
1109 
1110  HLocMin = 2000000000;
1111  VLocMin = 2000000000;
1112  HLocMax = -2000000000;
1113  VLocMax = -2000000000;
1114  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1115  CopyFlag = false; // only true for copying, so names aren't copied
1116 
1117  AnsiString NL = '\n';
1118 
1119  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1120  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1121  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1122  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1123 
1128 
1129  int InternalLinkCheckArray[9][2] =
1130  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1131 
1132 /* array of valid link values for 'old' location and 'new' location, where
1133  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1134 
1135  for(int x = 0; x < 9; x++)
1136  {
1137  for(int y = 0; y < 2; y++)
1138  {
1139  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1140  }
1141  }
1142 
1143 // Platform and default track element values
1144  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1145 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1146  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1147  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1148  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1149  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1150  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1151  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1152  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1153  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1154 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1155 
1156  int HVArray[10][2] =
1157  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1158 
1159  for(int x = 0; x < 10; x++)
1160  {
1161  for(int y = 0; y < 2; y++)
1162  {
1163  LinkHVArray[x][y] = HVArray[x][y];
1164  }
1165  }
1166  TrackFinished = false;
1167 // DistancesSet = false;
1168 
1169  TSigElement TempSigTable[40] = // original four aspect
1170  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1171  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1172 
1173  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1174  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1175 
1178 
1179  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1180  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1181 
1182  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1183  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1184  {75, 4, RailGraphics->gl75}};
1185 
1186  for(int x = 0; x < 40; x++)
1187  {
1188  SigTable[x] = TempSigTable[x];
1189  }
1190 
1191  TSigElement TempSigTableThreeAspect[40] =
1192  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1193  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1194 
1195  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1196  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1197 
1198  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1199  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1200 
1201  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1202  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1203 
1204  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1205  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1206  {75, 4, RailGraphics->gl75}};
1207 
1208  for(int x = 0; x < 40; x++)
1209  {
1210  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1211  }
1212 
1213  TSigElement TempSigTableTwoAspect[40] =
1214  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1215  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1216 
1217  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1218  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1219 
1220  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1221  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1222 
1223  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1224  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1225 
1226  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1227  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1228  {75, 4, RailGraphics->gl75}};
1229 
1230  for(int x = 0; x < 40; x++)
1231  {
1232  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1233  }
1234 
1235  TSigElement TempSigTableGroundSignal[40] =
1239 
1243 
1247 
1251 
1252  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1255 
1256  for(int x = 0; x < 40; x++)
1257  {
1258  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1259  }
1260 
1261 /*
1262  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1263  a single location. These are as follows:-
1264  Directly Adjacent = up, down, left or right - NOT diagonal.
1265  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1266  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1267  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1268 
1269  //t 76
1270  //b 77
1271  //l 78
1272  //r 79
1273  //c 96
1274  //v fb 129
1275  //h fb 130
1276  //v underpass 145
1277  //h underpass 146
1278  //n 131
1279 */
1280 
1281  int Tag76[25][3] =
1282  {{-1, 0, 96}, // c top plat
1283  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1284  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1285  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1286  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1287  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1288  {0, 0, 129}, {0, -1, 145}, // v up
1289  {0, 0, 145}};
1290 
1291  for(int x = 0; x < 25; x++)
1292  {
1293  for(int y = 0; y < 3; y++)
1294  {
1295  Tag76Array[x][y] = Tag76[x][y];
1296  }
1297  }
1298 
1299  int Tag77[25][3] =
1300  {{-1, 0, 96}, // c bot plat
1301  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1302  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1303  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1304  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1305  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1306  {0, 0, 129}, {0, 1, 145}, // v up
1307  {0, 0, 145}};
1308 
1309  for(int x = 0; x < 25; x++)
1310  {
1311  for(int y = 0; y < 3; y++)
1312  {
1313  Tag77Array[x][y] = Tag77[x][y];
1314  }
1315  }
1316 
1317  int Tag78[25][3] =
1318  {{-1, 0, 96}, // c left plat
1319  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1320  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1321  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1322  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1323  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1324  {0, 0, 130}, {-1, 0, 146}, // h up
1325  {0, 0, 146}};
1326 
1327  for(int x = 0; x < 25; x++)
1328  {
1329  for(int y = 0; y < 3; y++)
1330  {
1331  Tag78Array[x][y] = Tag78[x][y];
1332  }
1333  }
1334 
1335  int Tag79[25][3] =
1336  {{-1, 0, 96}, // c right plat
1337  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1338  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1339  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1340  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1341  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1342  {0, 0, 130}, {1, 0, 146}, // h up
1343  {0, 0, 146}};
1344 
1345  for(int x = 0; x < 25; x++)
1346  {
1347  for(int y = 0; y < 3; y++)
1348  {
1349  Tag79Array[x][y] = Tag79[x][y];
1350  }
1351  }
1352 
1353  int Tag96[28][3] =
1354  {{-1, 0, 96}, // c //concourse
1355  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1356  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1357  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1358  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1359  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1360  {0, -1, 129}, {1, 0, 130}, // h fb
1361  {-1, 0, 130}, {0, 1, 145}, // v up
1362  {0, -1, 145}, {1, 0, 146}, // h up
1363  {-1, 0, 146}};
1364 
1365  for(int x = 0; x < 28; x++)
1366  {
1367  for(int y = 0; y < 3; y++)
1368  {
1369  Tag96Array[x][y] = Tag96[x][y];
1370  }
1371  }
1372 
1373  int Tag129[8][3] = // vert fb
1374  {{0, -1, 96}, // c
1375  {0, -1, 77}, // b
1376  {0, -1, 129}, // v fb
1377 
1378  {0, 1, 96}, // c
1379  {0, 1, 76}, // t
1380  {0, 1, 129}, // v fb
1381 
1382  {0, 0, 76}, // t
1383  {0, 0, 77}}; // b
1384 
1385  for(int x = 0; x < 8; x++)
1386  {
1387  for(int y = 0; y < 3; y++)
1388  {
1389  Tag129Array[x][y] = Tag129[x][y];
1390  }
1391  }
1392 
1393  int Tag145[8][3] = // vert up
1394  {{0, -1, 96}, // c
1395  {0, -1, 77}, // b
1396  {0, -1, 145}, // v fb
1397 
1398  {0, 1, 96}, // c
1399  {0, 1, 76}, // t
1400  {0, 1, 145}, // v fb
1401 
1402  {0, 0, 76}, // t
1403  {0, 0, 77}}; // b
1404 
1405  for(int x = 0; x < 8; x++)
1406  {
1407  for(int y = 0; y < 3; y++)
1408  {
1409  Tag145Array[x][y] = Tag145[x][y];
1410  }
1411  }
1412 
1413  int Tag130[8][3] = // hor fb
1414  {{-1, 0, 96}, // c
1415  {-1, 0, 79}, // r
1416  {-1, 0, 130}, // h fb
1417 
1418  {1, 0, 96}, // c
1419  {1, 0, 78}, // l
1420  {1, 0, 130}, // h fb
1421 
1422  {0, 0, 78}, // l
1423  {0, 0, 79}}; // r
1424 
1425  for(int x = 0; x < 8; x++)
1426  {
1427  for(int y = 0; y < 3; y++)
1428  {
1429  Tag130Array[x][y] = Tag130[x][y];
1430  }
1431  }
1432 
1433  int Tag146[8][3] = // hor up
1434  {{-1, 0, 96}, // c
1435  {-1, 0, 79}, // r
1436  {-1, 0, 146}, // h fb
1437 
1438  {1, 0, 96}, // c
1439  {1, 0, 78}, // l
1440  {1, 0, 146}, // h fb
1441 
1442  {0, 0, 78}, // l
1443  {0, 0, 79}}; // r
1444 
1445  for(int x = 0; x < 8; x++)
1446  {
1447  for(int y = 0; y < 3; y++)
1448  {
1449  Tag146Array[x][y] = Tag146[x][y];
1450  }
1451  }
1452 
1453  int Tag131[4][3] =
1454  {{-1, 0, 131}, // n
1455  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1456 
1457  for(int x = 0; x < 4; x++)
1458  {
1459  for(int y = 0; y < 3; y++)
1460  {
1461  Tag131Array[x][y] = Tag131[x][y];
1462  }
1463  }
1464 
1465  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1466  {
1467  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1468  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1469  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1470  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1471  140, 144, 145, 146
1472  };
1473 
1474  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1475  {
1476  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1477  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1478  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1479  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1480  141, 144, 145, 146
1481  };
1482 
1483  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1484  {
1485  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1486  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1487  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1488  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1489  141, 144, 146, 145
1490  };
1491 
1492  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1493  {
1494  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1495  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1496  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1497  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1498  140, 144, 146, 145
1499  };
1500 
1501  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1502  {
1503  FlipArray[x] = InternalFlipArray[x];
1504  MirrorArray[x] = InternalMirrorArray[x];
1505  RotRightArray[x] = InternalRotRightArray[x];
1506  RotLeftArray[x] = InternalRotLeftArray[x];
1507  }
1508 }
1509 
1510 // ---------------------------------------------------------------------------
1512 {
1513 // delete TrackVectorPtr;
1514 // delete FixedTrackArrayPtr;
1515  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1516 
1517  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1518  {
1519  delete UGMIt->second;
1520  UGMIt++;
1521  }
1522  delete GapFlashGreen;
1523  delete GapFlashRed;
1524  // all the rest are cleared by the relevant automatic destructors
1525 }
1526 
1527 // ---------------------------------------------------------------------------
1528 
1530 {
1531  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1532  {
1533 // loc 0 not used, set to bmSolidBgnd
1537 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1557  };
1558 
1559  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1560  {
1561 // loc 0 not used, set to smSolidBgnd
1565 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1584  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1585  };
1586 
1587 // track types
1588  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1589  {
1590  Erase, // 1 0
1591  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1592  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1593  Crossover, Crossover, // 2 15-16
1594  Unused, // 17 (was for text in earlier development) //1 17
1597  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1601  Platform, Platform, Platform, Platform, // 4 76-79
1604  Concourse, // 1 96
1607  Simple, Simple, Simple, Simple, // 4 125-128
1608  FootCrossing, FootCrossing, // 2 129-130
1609  NamedNonStationLocation, // 1 131
1610  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1611  Simple, Simple, Simple, Simple, // 4 140-143
1612  LevelCrossing, // 1 144
1613  FootCrossing, FootCrossing // 2 145 & 146
1614  };
1615 
1616 // links
1617  int Links[FirstUnusedSpeedTagNumber][4] =
1618  {{-1, -1, -1, -1}, // erase element
1619  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1620  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1621 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1622  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1623  {-1, -1, -1, -1}, // unused
1624  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1625  {2, 7, -1, -1}, // simple
1626  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1627 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1628 // (or right diverging if no straight)
1629  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1630  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1631  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1632  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1633  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1634  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1635  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1636  {-1, -1, -1, -1}, // Concourse
1637  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1638  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1639  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1640  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1641  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1642  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1643  {-1, -1, -1, -1}, // NamedNonStationLocation
1644  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1645 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1646  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1647  {-1, -1, -1, -1}, // level crossing
1648  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1649  };
1650 
1652  {{NotSet, NotSet, NotSet, NotSet}, // unused
1656  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1658  {NotSet, NotSet, NotSet, NotSet}, // unused
1662  {Connection, Connection, NotSet, NotSet}, // simple
1666  {Lead, Trail, Lead, Trail}, // points
1668  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1676  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1682  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1691  {Connection, Connection, NotSet, NotSet}, // Arrows
1693  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1695  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1697  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1698  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1699  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1700  };
1701 
1702  for(int x = 0; x < 17; x++)
1703  {
1704  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1705  }
1706  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1707 // 17 was the old text value so don't want any graphics (now disused)
1708  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1709  {
1710  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1711  }
1712 }
1713 
1714 // ---------------------------------------------------------------------------
1715 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1716  ExistingGraphicLoaded(false), Width(16), Height(16)
1717 {
1718  OriginalGraphic = new Graphics::TBitmap;
1719  OriginalGraphic->PixelFormat = pf8bit;
1720  OriginalGraphic->Width = Width;
1721  OriginalGraphic->Height = Height;
1722  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1723 }
1724 
1725 // ---------------------------------------------------------------------------
1726 
1727 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1728  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1729 {
1730  OriginalGraphic = new Graphics::TBitmap;
1731  OriginalGraphic->PixelFormat = pf8bit;
1732  OriginalGraphic->Width = Width;
1733  OriginalGraphic->Height = Height;
1734  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1735 }
1736 
1737 // ---------------------------------------------------------------------------
1738 
1740 {
1741  delete OriginalGraphic;
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1747 {
1748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1749  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1750  VPos = VPosIn;
1751  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1752 
1753  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1754  SourceRect.init(Left, Top, Left + Width, Top + Height);
1755  ScreenSourceSet = true;
1756  Utilities->CallLogPop(422);
1757 }
1758 
1759 // ---------------------------------------------------------------------------
1760 
1762 {
1763  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1764  if(!OverlayLoaded)
1765  {
1766  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1767  }
1768  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1769  {
1770  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1771  }
1772  if(!ScreenSourceSet)
1773  {
1774  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1775  }
1776  if(ExistingGraphicLoaded) // can only call one of the load functions
1777  {
1778  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1779  }
1780  if(OverlayPlotted) // don't load from screen if overlay plotted
1781  {
1782  Utilities->CallLogPop(775);
1783  return;
1784  }
1785  TRect DestRect(0, 0, Width, Height);
1786 
1788  OriginalLoaded = true;
1789  ScreenGraphicLoaded = true;
1790  Utilities->CallLogPop(423);
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1796 /*
1797  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1798 */
1799 {
1800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1801  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1802  if(!OverlayLoaded)
1803  {
1804  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1805  }
1806  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1807  {
1808  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1809  }
1810  if(ScreenGraphicLoaded) // can only call one of the load functions
1811  {
1812  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1813  }
1814  Width = WidthIn;
1815  Height = HeightIn;
1816  OriginalGraphic->Width = Width;
1817  OriginalGraphic->Height = Height;
1818  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1819  VPos += VOffset;
1820  TRect DestRect(0, 0, Width, Height);
1821 
1822  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1823  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1824  OriginalLoaded = true;
1825  ExistingGraphicLoaded = true;
1826  Utilities->CallLogPop(424);
1827 }
1828 
1829 // ---------------------------------------------------------------------------
1830 
1831 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1832 {
1833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1834  OverlayGraphic = Overlay;
1835  OverlayLoaded = true;
1836  Utilities->CallLogPop(425);
1837 }
1838 
1839 // ---------------------------------------------------------------------------
1840 
1842 {
1843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1844  if(!OverlayLoaded)
1845  {
1846  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1847  }
1848  if(!OverlayPlotted)
1849  {
1850  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1851  Disp->Update();
1852  OverlayPlotted = true;
1853  }
1854  Utilities->CallLogPop(426);
1855 }
1856 
1857 // ---------------------------------------------------------------------------
1858 
1860 {
1861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1862  if(OverlayPlotted)
1863  {
1864  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1865  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1866  {
1867  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1868  }
1869  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1870  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1871  OverlayPlotted = false;
1872  }
1873  Utilities->CallLogPop(427);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1881  bool TrackPresent = false;
1882 
1883  if(InactiveTrackVector.size() != 0)
1884  {
1885  Utilities->CallLogPop(1333);
1886  return(false);
1887  }
1888  else if(TrackVector.size() == 0)
1889  {
1890  Utilities->CallLogPop(1334);
1891  return(true);
1892  }
1893  else
1894  {
1895  for(unsigned int x = 0; x < TrackVector.size(); x++)
1896  {
1897  if((TrackElementAt(1042, x).SpeedTag != 0))
1898  {
1899  TrackPresent = true;
1900  }
1901  }
1902  }
1903  Utilities->CallLogPop(1335);
1904  return(!TrackPresent);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1909 bool TTrack::NoActiveTrack(int Caller)
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1912  bool TrackPresent = false;
1913 
1914  if(TrackVector.size() == 0)
1915  {
1916  Utilities->CallLogPop(1582);
1917  return(true);
1918  }
1919  else
1920  {
1921  for(unsigned int x = 0; x < TrackVector.size(); x++)
1922  {
1923  if((TrackElementAt(1043, x).SpeedTag != 0))
1924  {
1925  TrackPresent = true;
1926  }
1927  break;
1928  }
1929  }
1930  Utilities->CallLogPop(1583);
1931  return(!TrackPresent);
1932 }
1933 
1934 // ---------------------------------------------------------------------------
1935 
1936 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1937 {
1938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1939  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1940  TrackEraseSuccessfulFlag = false;
1941 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1942 // since have to match platforms as well as track
1943 // used to set TrackFinished to false if an element erased
1944 
1945  ErasedTrackVectorPosition = -1; // marker for no element erased
1946  AnsiString SName = "", ErrorString;
1948  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1949  TTrackMapIterator TrackMapPtr;
1950  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1951 
1952  if(TrackVector.size() != 0)
1953  {
1954  TrackMapKeyPair.first = HLocInput;
1955  TrackMapKeyPair.second = VLocInput;
1956  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1957  if(TrackMapPtr != TrackMap.end())
1958  {
1959  bool FoundFlag;
1960  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1961  if(FoundFlag) // should find it as it's in the map
1962  {
1963  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1964  {
1965  SName = TrackElementAt(1, VecPos).LocationName;
1966  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1967  if(ErrorString != "")
1968  {
1969  throw Exception(ErrorString + " for EraseTrackElement 1");
1970  }
1971  LocationNameMultiMap.erase(SNIt);
1972  }
1973  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1974  // ensure erase vector element before map element as iterator no longer valid after a map erase
1975  TrackMap.erase(TrackMapPtr);
1976  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1977  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1979  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1980  if(SName != "")
1981  {
1982  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1983  int HPos, VPos;
1984  if(TextHandler->FindText(1, SName, HPos, VPos))
1985  {
1986  if(TextHandler->TextErase(5, HPos, VPos, SName))
1987  {
1988  ;
1989  } // condition not used
1990 
1991  }
1992  }
1993  ErasedTrackVectorPosition = VecPos;
1994  TrackEraseSuccessfulFlag = true;
1995  }
1996  }
1997  }
1998  if(InactiveTrackVector.size() != 0)
1999  {
2000  unsigned int VecPos;
2001  InactiveTrackMapKeyPair.first = HLocInput;
2002  InactiveTrackMapKeyPair.second = VLocInput;
2003  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2004  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2005  {
2006  SName = "";
2007  VecPos = InactiveTrack2MultiMapIterator->second;
2008  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2009  {
2010  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2011  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2012  if(ErrorString != "")
2013  {
2014  throw Exception(ErrorString + " for EraseTrackElement 2A");
2015  }
2016  LocationNameMultiMap.erase(SNIt);
2017  }
2018  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2019  // ensure erase vector element before map element as iterator no longer valid after a map erase
2020  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2021  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2022  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2024  TrackEraseSuccessfulFlag = true;
2025  if(SName != "")
2026  {
2027  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2028  int HPos, VPos;
2029  if(TextHandler->FindText(2, SName, HPos, VPos))
2030  {
2031  if(TextHandler->TextErase(6, HPos, VPos, SName))
2032  {
2033  ;
2034  } // condition not used
2035 
2036  }
2037  }
2038  }
2039  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2040  {
2041  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2042  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2043  {
2044  SName = "";
2045  VecPos = InactiveTrack2MultiMapIterator->second;
2046  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2047  {
2048  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2049  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2050  if(ErrorString != "")
2051  {
2052  throw Exception(ErrorString + " for EraseTrackElement 2B");
2053  }
2054  LocationNameMultiMap.erase(SNIt);
2055  }
2056  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2057  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2058  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2060  if(SName != "")
2061  {
2062  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2063  int HPos, VPos;
2064  if(TextHandler->FindText(3, SName, HPos, VPos))
2065  {
2066  if(TextHandler->TextErase(7, HPos, VPos, SName))
2067  {
2068  ;
2069  } // condition not used
2070 
2071  }
2072  }
2073  }
2074  }
2075  }
2076  if(TrackEraseSuccessfulFlag)
2077  {
2078  CalcHLocMinEtc(2);
2079  SetTrackFinished(false);
2080  }
2081  if(InternalChecks)
2082  {
2083  CheckMapAndTrack(1); // test
2084  CheckMapAndInactiveTrack(1); // test
2085  CheckLocationNameMultiMap(6); // test
2086  }
2087  Utilities->CallLogPop(428);
2088 }
2089 
2090 // ---------------------------------------------------------------------------
2091 
2092 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2093 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2094 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2095 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2096 {
2097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2098  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2099  bool PlatAllowedFlag = false;
2100 
2101  TrackLinkingRequiredFlag = false;
2102 /*
2103  Not erase, that covered separately.
2104  First check if Current SpeedButton assigned, then check if a platform and only
2105  permit if an appropriate trackpiece already there & not a same platform there.
2106  - can't enter a platform without track first.
2107  Then for non-platforms, check if a track piece already present at location &
2108  reject if so.
2109 */
2110 
2111  TLocationNameMultiMapEntry LocationNameEntry;
2112 
2113  LocationNameEntry.first = "";
2114  if(CurrentTag == 0)
2115  {
2116  Utilities->CallLogPop(429);
2117  return; // not assigned yet
2118  }
2119  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2120 
2121  TempTrackElement.HLoc = HLocInput;
2122  TempTrackElement.VLoc = VLocInput;
2123  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2124 // new at version 0.6 - set signal aspect depending on build mode
2125 
2126  if(TempTrackElement.TrackType == SignalPost)
2127  {
2128  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2129  // pasting a SignalPost can only have values 1 to 4
2130  {
2132  {
2133  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2134  }
2136  {
2137  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2138  }
2140  {
2141  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2142  }
2143  else
2144  {
2145  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2146  }
2147  }
2148  else if(Aspect == 1)
2149  {
2150  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2151  }
2152  else if(Aspect == 2)
2153  {
2154  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2155  }
2156  else if(Aspect == 3)
2157  {
2158  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2159  }
2160  else
2161  {
2162  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2163  }
2164  }
2165  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2166  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2167  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2168  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2169 
2170  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2171  {
2173  {
2174  NonStationOrLevelCrossingPresent = true;
2175  }
2176  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2177  {
2178  NonStationOrLevelCrossingPresent = true;
2179  }
2180  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2181  {
2182  PlatformPresent = true;
2183  }
2184  // no need to check IMPair.second since if that exists it is because .first is a platform
2185  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2186  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2187  }
2188 // check platforms
2189  if(TempTrackElement.TrackType == Platform)
2190  {
2191  if(FoundFlag) // active track element already there
2192  {
2193  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2194  {
2195  ;
2196  }
2197  // same platform type already there so above keeps PlatAllowedFlag false
2198  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2199  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2200  {
2201  PlatAllowedFlag = true;
2202  }
2203  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2204  {
2205  PlatAllowedFlag = true;
2206  }
2207  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2208  {
2209  PlatAllowedFlag = true;
2210  }
2211  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2212  {
2213  PlatAllowedFlag = true;
2214  }
2215  if(PlatAllowedFlag)
2216  {
2217  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2218  TrackPush(1, TempTrackElement);
2219  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2220  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2221  // Must be called AFTER TrackPush
2222  // No need to plot the element - Clearand ... called after this function called
2223  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2224  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2225 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2226 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2227 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2228  if(InternalChecks)
2229  {
2230  CheckMapAndInactiveTrack(5); // test
2231  CheckLocationNameMultiMap(4); // test
2232  }
2233  Utilities->CallLogPop(430);
2234  return;
2235  }
2236  } // if(FoundFlag)
2237 
2238  Utilities->CallLogPop(431);
2239  return;
2240  } // if platform
2241 
2242 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2243  if(TempTrackElement.TrackType == NamedNonStationLocation)
2244  {
2245  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2246  (!FoundFlag && !InactiveFoundFlag))
2247  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2248  {
2249  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2250  TrackPush(2, TempTrackElement);
2251  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2252  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2253  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2254  {
2255 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2256 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2257 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2258  }
2259  if(InternalChecks)
2260  {
2261  CheckMapAndInactiveTrack(11); // test
2262  CheckLocationNameMultiMap(12); // test
2263  }
2264  Utilities->CallLogPop(432);
2265  return;
2266  }
2267  else
2268  {
2269  Utilities->CallLogPop(433);
2270  return;
2271  }
2272  }
2273 // check if a level crossing - OK if placed on a plain straight track
2274  if(TempTrackElement.TrackType == LevelCrossing)
2275  {
2276  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2277  {
2278  TrackPush(11, TempTrackElement);
2279  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2280 // no need for reference to LC element as can't be open
2281  TrackLinkingRequiredFlag = true;
2282  Utilities->CallLogPop(1907);
2283  return;
2284  }
2285  else
2286  {
2287  Utilities->CallLogPop(1906);
2288  return; // was a level crossing but can't place it for some reason
2289  }
2290  }
2291 
2292 // check if another element already there
2293  else if(FoundFlag || InactiveFoundFlag)
2294  {
2295  Utilities->CallLogPop(434);
2296  return; // something already there (active or inactive track)
2297  }
2298 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2299 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2300 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2301 // do this after pushed into vector so that can use EnterLocationName
2302 
2303  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2304  {
2305  TrackPush(3, TempTrackElement);
2306  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2307  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2308  }
2309  else if(TempTrackElement.TrackType == Points)
2310  {
2311  TrackPush(4, TempTrackElement);
2312  bool BothPointFillets = true;
2313  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2314  }
2315  else if(TempTrackElement.TrackType == SignalPost)
2316  {
2317  TrackPush(10, TempTrackElement);
2318  PlotSignal(12, TempTrackElement, Display);
2319  }
2320  else
2321  {
2322  TrackPush(5, TempTrackElement);
2323  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2324  }
2325  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2326  {
2327  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2328  }
2329  if(InternalChecks)
2330  {
2331  CheckMapAndTrack(2); // test
2332  CheckMapAndInactiveTrack(2); // test
2333  CheckLocationNameMultiMap(5); // test
2334  }
2335  Utilities->CallLogPop(2062);
2336 }
2337 
2338 // ---------------------------------------------------------------------------
2339 
2340 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2341  bool InternalChecks)
2342 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2343 {
2344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2345  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2346  bool PlatAllowedFlag = false;
2347 
2348  TrackLinkingRequiredFlag = false;
2349  TLocationNameMultiMapEntry LocationNameEntry;
2350 
2351  LocationNameEntry.first = "";
2352  if(TempTrackElement.SpeedTag == 0)
2353  {
2354  Utilities->CallLogPop(2063);
2355  return; // not assigned yet
2356  }
2357  TempTrackElement.HLoc = HLocInput;
2358  TempTrackElement.VLoc = VLocInput;
2359  for(int x = 0; x < 4; x++) // unset any gaps
2360  {
2361  if(TempTrackElement.Config[x] == Gap)
2362  {
2363  TempTrackElement.ConnLinkPos[x] = -1;
2364  }
2365  TempTrackElement.Conn[x] = -1;
2366  }
2367  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2368 // new at version 0.6 - set signal aspect depending on build mode
2369  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2370  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2371 
2372  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2373  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2374  // for the active track element because these aren't set
2375  // if don't do this then get a mismatch error during map checks later
2376 
2377  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2378 
2379  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2380  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2381 
2382  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2383  {
2384  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2385  {
2386  NonStationOrLevelCrossingPresent = true;
2387  }
2388  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2389  {
2390  NonStationOrLevelCrossingPresent = true;
2391  }
2392  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2393  {
2394  PlatformPresent = true;
2395  }
2396  // no need to check IMPair.second since if that exists it is because .first is a platform
2397  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2398  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2399  }
2400 // check platforms
2401  if(TempTrackElement.TrackType == Platform)
2402  {
2403  if(FoundFlag) // active track element already there
2404  {
2405  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2406  {
2407  ;
2408  }
2409  // same platform type already there so above keeps PlatAllowedFlag false
2410  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2411  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2412  {
2413  PlatAllowedFlag = true;
2414  }
2415  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2416  {
2417  PlatAllowedFlag = true;
2418  }
2419  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2420  {
2421  PlatAllowedFlag = true;
2422  }
2423  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2424  {
2425  PlatAllowedFlag = true;
2426  }
2427  if(PlatAllowedFlag)
2428  {
2429  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2430  TrackPush(12, TempTrackElement);
2431 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2432  {
2433  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2434  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2435  }
2436  // Must be called AFTER TrackPush
2437 // No need to plot the element - Clearand ... called after this function called
2438  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2439  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2440 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2441 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2442 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2443  if(InternalChecks)
2444  {
2445  CheckMapAndInactiveTrack(12); // test
2446  CheckLocationNameMultiMap(20); // test
2447  }
2448  Utilities->CallLogPop(2064);
2449  return;
2450  }
2451  } // if(FoundFlag)
2452 
2453  Utilities->CallLogPop(2065);
2454  return;
2455  } // if platform
2456 
2457 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2458  if(TempTrackElement.TrackType == NamedNonStationLocation)
2459  {
2460  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2461  (!FoundFlag && !InactiveFoundFlag))
2462  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2463  {
2464  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2465  TrackPush(13, TempTrackElement);
2466 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2467  {
2468  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2469  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2470  }
2471  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2472  {
2473 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2474 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2475 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2476  }
2477  if(InternalChecks)
2478  {
2479  CheckMapAndInactiveTrack(13); // test
2480  CheckLocationNameMultiMap(21); // test
2481  }
2482  Utilities->CallLogPop(2066);
2483  return;
2484  }
2485  else
2486  {
2487  Utilities->CallLogPop(2067);
2488  return;
2489  }
2490  }
2491 // check if a level crossing - OK if placed on a plain straight track
2492  if(TempTrackElement.TrackType == LevelCrossing)
2493  {
2494  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2495  {
2496  TrackPush(14, TempTrackElement);
2497  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2498 // no need for reference to LC element as can't be open
2499  TrackLinkingRequiredFlag = true;
2500  Utilities->CallLogPop(2068);
2501  return;
2502  }
2503  else
2504  {
2505  Utilities->CallLogPop(2069);
2506  return; // was a level crossing but can't place it for some reason
2507  }
2508  }
2509 
2510 // check if another element already there
2511  else if(FoundFlag || InactiveFoundFlag)
2512  {
2513  Utilities->CallLogPop(2070);
2514  return; // something already there (active or inactive track)
2515  }
2516 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2517 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2518 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2519 // do this after pushed into vector so that can use EnterLocationName
2520 
2521  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2522  {
2523  TrackPush(15, TempTrackElement);
2524  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2525  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2526  }
2527  else if(TempTrackElement.TrackType == Points)
2528  {
2529  TrackPush(16, TempTrackElement);
2530  bool BothPointFillets = true;
2531  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2532  }
2533  else if(TempTrackElement.TrackType == SignalPost)
2534  {
2535  TrackPush(17, TempTrackElement);
2536  PlotSignal(14, TempTrackElement, Display);
2537  }
2538  else
2539  {
2540  TrackPush(18, TempTrackElement);
2541  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2542  }
2543  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2544  {
2545  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2546  }
2547  if(InternalChecks)
2548  {
2549  CheckMapAndTrack(12); // test
2550  CheckMapAndInactiveTrack(14); // test
2551  CheckLocationNameMultiMap(22); // test
2552  }
2553  Utilities->CallLogPop(2071);
2554 }
2555 
2556 // ---------------------------------------------------------------------------
2557 
2558 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2559 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2560 // return bool = true for success
2561 // LocError = true for location error & HLoc & VLoc to be inverted
2562 {
2563  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2564  LocError = false;
2565  SetTrackFinished(false);
2566  if(TrackVector.size() == 0)
2567  {
2568  Utilities->CallLogPop(437);
2569  return(false);
2570  }
2571  if(GapsUnset(7))
2572  {
2573  if(GiveMessages)
2574  {
2575  ShowMessage("Gaps must be set before track can be validated");
2576  }
2577  Utilities->CallLogPop(1135);
2578  return(false);
2579  }
2580 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2581 // returns true for any unset gaps
2583  {
2584  // can keep this exception as protected by the GapsUnset call above
2585  throw Exception("Error, gaps unset when TryToConnectTrack called");
2586  }
2588  CheckGapMap(1); // test
2589 // Gap connections now securely defined
2590 
2591  CheckMapAndTrack(8); // test
2592 
2593 // Perform a pre-check prior to TrackMap being compiled
2594  if(GiveMessages)
2595  {
2596  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2597  {
2598  Utilities->CallLogPop(439);
2599  return(false);
2600  }
2601  }
2602  else
2603  {
2604  if(!LinkTrackNoMessages(1, false))
2605  {
2606  Utilities->CallLogPop(1131);
2607  return(false);
2608  }
2609  }
2610 // here if pre-check successful
2611  if(!RepositionAndMapTrack(0))
2612  {
2613  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2614  Utilities->CallLogPop(1138);
2615  return(false);
2616  }
2617 // now perform the final assembly - FinalCall = true
2618  if(GiveMessages)
2619  {
2620  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2621  {
2622  Utilities->CallLogPop(1116);
2623  return(false);
2624  }
2625  }
2626  else
2627  {
2628  if(!LinkTrackNoMessages(2, true))
2629  {
2630  Utilities->CallLogPop(1132);
2631  return(false);
2632  }
2633  }
2634 // success
2635 
2636  PopulateLCVector(0);
2637  CheckGapMap(2); // test
2638  CheckMapAndTrack(3); // test
2639  CheckMapAndInactiveTrack(3); // test
2640  CheckLocationNameMultiMap(9); // test
2641  SetTrackFinished(true);
2642 
2643 // Build ContinuationNameMap
2644  std::pair<AnsiString, char>TempMapPair;
2645 
2646  ContinuationNameMap.clear();
2647  for(int x = 0; x < Track->TrackVectorSize(); x++)
2648  {
2649  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2650  {
2651  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2652  TempMapPair.second = 'x'; // unused
2653  ContinuationNameMap.insert(TempMapPair);
2654  }
2655  }
2656  Utilities->CallLogPop(440);
2657  return(true);
2658 }
2659 
2660 // ---------------------------------------------------------------------------
2661 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2662 // unused - too time-consuming - double brute force search
2663 {
2664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2665  int NewHLoc, NewVLoc;
2666  bool ConnectionFoundFlag, LinkFoundFlag;
2667 
2668  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2669  {
2670  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2671  {
2672  if(TrackElementAt(1061, x).Link[y] <= 0)
2673  {
2674  continue; // no link
2675  }
2676  if(TrackElementAt(1062, x).Config[y] == End)
2677  {
2678  continue; // buffer or continuation
2679  }
2680  if(TrackElementAt(1063, x).Config[y] == Gap)
2681  {
2682  continue; // gap jump
2683  }
2684  // get required H & V for track element joining link 'y'
2685  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2686  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2687  // find track element if present
2688  ConnectionFoundFlag = false;
2689  for(unsigned int z = 0; z < TrackVector.size(); z++)
2690  {
2691 // if(TrackElementAt(5, z).TrackType == Platform)
2692 // continue; //skip platforms
2693  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2694  {
2695  ConnectionFoundFlag = true;
2696  // find connecting link in the newly found track element if there is one
2697  LinkFoundFlag = false;
2698  for(unsigned int a = 0; a < 4; a++)
2699  {
2700  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2701  {
2702  LinkFoundFlag = true;
2703  }
2704  }
2705  // if there isn't a corresponding link set the invert values for the offending element
2706  if(!LinkFoundFlag)
2707  {
2708  HLoc = TrackElementAt(1072, x).HLoc;
2709  VLoc = TrackElementAt(1073, x).VLoc;
2710  Utilities->CallLogPop(441);
2711  return(true);
2712  }
2713  break; // success, so break out of 'z' loop
2714  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2715 
2716  } // for z...
2717  // if there isn't a connection set the invert values for the offending element
2718  if(!ConnectionFoundFlag)
2719  {
2720  HLoc = TrackElementAt(1074, x).HLoc;
2721  VLoc = TrackElementAt(1075, x).VLoc;
2722  Utilities->CallLogPop(442);
2723  return(true);
2724  }
2725  } // for y....
2726  } // for x...
2727  Utilities->CallLogPop(443);
2728  return(false); // all OK
2729 }
2730 
2731 // ---------------------------------------------------------------------------
2732 
2733 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2734 {
2735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2736  TrackElement.LogTrack(0));
2737  bool FoundFlag;
2738 
2739  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2740  if(FoundFlag)
2741  {
2742  TrackElement = TrackElementAt(1076, Position);
2743  }
2744  Utilities->CallLogPop(444);
2745  return(FoundFlag);
2746 }
2747 
2748 // ---------------------------------------------------------------------------
2749 
2751 {
2752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2753  if(NextTrackElementPtr >= TrackVector.end())
2754  {
2755  Utilities->CallLogPop(1336);
2756  return(false);
2757  }
2758  Next = *NextTrackElementPtr;
2760  Utilities->CallLogPop(1337);
2761  return(true);
2762 }
2763 
2764 // ---------------------------------------------------------------------------
2765 
2767 {
2768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2770  {
2771  Utilities->CallLogPop(1338);
2772  return(false);
2773  }
2774  Next = *NextTrackElementPtr;
2776  Utilities->CallLogPop(1339);
2777  return(true);
2778 }
2779 
2780 // ---------------------------------------------------------------------------
2781 
2782 int TTrack::NumberOfGaps(int Caller)
2783 
2784 {
2785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2786  int Count = 0;
2787 
2788  if(TrackVector.size() == 0)
2789  {
2790  Utilities->CallLogPop(1340);
2791  return(0);
2792  }
2793  for(unsigned int x = 0; x < TrackVector.size(); x++)
2794  {
2795  if(TrackElementAt(1077, x).TrackType == GapJump)
2796  {
2797  Count++;
2798  }
2799  }
2800  Utilities->CallLogPop(1341);
2801  return(Count);
2802 }
2803 
2804 // ---------------------------------------------------------------------------
2806 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2807 // returns true for any unset gaps
2808 {
2809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2810  bool UnsetGaps = false;
2811 
2812  if(TrackVector.size() == 0)
2813  {
2814  Utilities->CallLogPop(445);
2815  return(false);
2816  }
2817  for(unsigned int x = 0; x < TrackVector.size(); x++)
2818  {
2819  if(TrackElementAt(1078, x).TrackType != GapJump)
2820  {
2821  for(unsigned int y = 0; y < 4; y++)
2822  {
2823  TrackElementAt(1079, x).Conn[y] = -1;
2824  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2825  }
2826  }
2827  else // GapJump
2828  {
2829 // int tempint = TrackElementAt(, x).Conn[0);
2830 
2831  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2832  {
2833  for(unsigned int y = 0; y < 4; y++)
2834  {
2835  TrackElementAt(1082, x).Conn[y] = -1;
2836  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2837  }
2838  UnsetGaps = true;
2839  continue; // to next 'x'
2840  }
2841  else // set, but may not have matching element, or that element may not be set
2842  {
2843  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2844  {
2845  TrackElementAt(1084, x).Conn[y] = -1;
2846  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2847  }
2848 
2849  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2850  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2851  {
2852  for(unsigned int y = 0; y < 4; y++)
2853  {
2854  TrackElementAt(1087, x).Conn[y] = -1;
2855  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2856  }
2857  UnsetGaps = true;
2858  continue; // to next 'x'
2859  }
2860 // here if gap connection is itself a GapJump
2861  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2862  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2863  // if not clear Conns & CLks & reset Lk[0]
2864  {
2865  for(unsigned int y = 0; y < 4; y++)
2866  {
2867  TrackElementAt(1090, x).Conn[y] = -1;
2868  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2869  }
2870  UnsetGaps = true;
2871  continue; // to next 'x'
2872  }
2873 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2874 // hence no more action needed on these Conns & CLks
2875  }
2876  } // else //gap jump
2877 
2878  } // for x...
2879  Utilities->CallLogPop(446);
2880  return(UnsetGaps);
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2886 {
2887 // VecFile already open and its pointer at right place on calling
2888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2889  int TempInt;
2890 
2891  TrackClear(1);
2892 // load track elements
2893  int NumberOfActiveElements = 0;
2894 
2895  GraphicsFollow = false;
2896  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2897  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2898 
2899  if(MarkerString[MarkerString.Length()] == '1')
2900  {
2901  GraphicsFollow = true;
2902  }
2903  for(int x = 0; x < NumberOfActiveElements; x++)
2904  {
2905  VecFile >> TempInt; // TrackVectorNumber, not used
2906  VecFile >> TempInt; // SpeedTag
2907  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2908  VecFile >> TempInt;
2909  TrackElement.HLoc = TempInt;
2910  VecFile >> TempInt;
2911  TrackElement.VLoc = TempInt;
2912  if(TrackElement.TrackType == GapJump)
2913  {
2914  VecFile >> TempInt;
2915  TrackElement.ConnLinkPos[0] = TempInt;
2916  VecFile >> TempInt;
2917  TrackElement.Conn[0] = TempInt;
2918  }
2919  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2920  {
2921  VecFile >> TempInt;
2922  TrackElement.Attribute = TempInt;
2923  }
2924  if(TrackElement.TrackType == SignalPost)
2925  {
2926  VecFile >> TempInt;
2927  if(TempInt == 0)
2928  {
2929  TrackElement.CallingOnSet = false;
2930  }
2931  else
2932  {
2933  TrackElement.CallingOnSet = true;
2934  }
2935  }
2936  VecFile >> TempInt;
2937  TrackElement.Length01 = TempInt;
2938  VecFile >> TempInt;
2939  TrackElement.Length23 = TempInt;
2940  VecFile >> TempInt;
2941  if((TempInt != -1) && (TempInt < 10))
2942  {
2943  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2944  }
2945  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2946  {
2947  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2948  }
2949  TrackElement.SpeedLimit01 = TempInt;
2950  VecFile >> TempInt;
2951  if((TempInt != -1) && (TempInt < 10))
2952  {
2953  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2954  }
2955  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2956  {
2957  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2958  }
2959  TrackElement.SpeedLimit23 = TempInt;
2960 
2961  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2962  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2963  SetElementID(0, TrackElement);
2964  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2965 // new for v0.6
2966  if(TrackElement.TrackType == SignalPost)
2967  {
2968  if(Marker[1] == '3')
2969  {
2970  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2971  }
2972  else if(Marker[1] == '2')
2973  {
2974  TrackElement.SigAspect = TTrackElement::TwoAspect;
2975  }
2976  else if(Marker[1] == 'G')
2977  {
2978  TrackElement.SigAspect = TTrackElement::GroundSignal;
2979  }
2980  else
2981  {
2982  TrackElement.SigAspect = TTrackElement::FourAspect;
2983  }
2984  }
2985  if(TrackElement.SpeedTag != 0)
2986  {
2987  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2988  }
2989  }
2990  int NumberOfInactiveElements = 0;
2991 
2992  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2993  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2994  for(int x = 0; x < NumberOfInactiveElements; x++)
2995  {
2996  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3004  SetElementID(3, TrackElement);
3005  TrackPush(9, TrackElement);
3006  Utilities->LoadFileString(VecFile); // marker
3007  }
3008  bool LocError = false; // needed for TryToConnectTrack but not used
3009  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3010 
3011  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3012  {
3013  SetTrackFinished(true);
3014  }
3015  else
3016  {
3017  SetTrackFinished(false);
3018  }
3019 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3020 // CheckMapAndInactiveTrack(8);
3021 // CheckLocationNameMultiMap(10);
3022  Utilities->CallLogPop(448);
3023 }
3024 
3025 // ---------------------------------------------------------------------------
3026 
3027 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3028 {
3029 // VecFile already open and its pointer at right place on calling
3030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3031 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3032 // & load into UserGraphicItem then store in UserGraphicVector
3033  UserGraphicVector.clear();
3034  TUserGraphicItem UGI;
3035  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3036 
3037  for(int x = 0; x < NumberOfGraphics; x++)
3038  {
3039  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3040  UGI.HPos = Utilities->LoadFileInt(VecFile);
3041  UGI.VPos = Utilities->LoadFileInt(VecFile);
3042  UGI.Width = 0; // provisional value
3043  UGI.Height = 0; // provisional value
3044  UGI.UserGraphic = NULL; // provisional value
3045  UserGraphicVector.push_back(UGI);
3046  }
3047 // now load the map & set Width, Height & TPicture*
3048  bool FileError = false;
3049 
3050  for(int x = 0; x < NumberOfGraphics; x++)
3051  {
3052  if(FileError)
3053  {
3054  break; // otherwise keeps going round the loop
3055  }
3056  UGI = UserGraphicVectorAt(0, x);
3057  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3058  {
3059  try
3060  {
3061 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3062  UGME.first = UGI.FileName;
3063  UGME.second = new TPicture;
3064  UGME.second->LoadFromFile(UGME.first); // errors caught below
3065  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3066  {
3067  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3068  }
3069  UGI.UserGraphic = UGME.second;
3070  UGI.Width = UGI.UserGraphic->Width;
3071  UGI.Height = UGI.UserGraphic->Height;
3072  UserGraphicVectorAt(1, x) = UGI;
3073  }
3074  catch(const EInvalidGraphic &e) //non error catch
3075  {
3076  //message already sent in CheckUserGraphics
3077  FileError = true;
3078  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3079  if(!UserGraphicMap.empty())
3080  {
3081  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3082  {
3083  delete UGMIt->second;
3084  }
3085  UserGraphicMap.clear();
3086  }
3087  }
3088  catch(const Exception &e) //non error catch
3089  {
3090  //message already sent in CheckUserGraphics
3091  FileError = true;
3092  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3093  if(!UserGraphicMap.empty())
3094  {
3095  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3096  {
3097  delete UGMIt->second;
3098  }
3099  UserGraphicMap.clear();
3100  }
3101  }
3102  }
3103  else
3104  {
3105  bool FoundInMap = false;
3106  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3107  {
3108  if(UGI.FileName == UGMIt->first) // already exists in map
3109  {
3110  UGI.UserGraphic = UGMIt->second;
3111  UGI.Width = UGI.UserGraphic->Width;
3112  UGI.Height = UGI.UserGraphic->Height;
3113  UserGraphicVectorAt(2, x) = UGI;
3114  FoundInMap = true;
3115  break;
3116  }
3117  }
3118  if(!FoundInMap)
3119  {
3120  try
3121  {
3123  UGME.first = UGI.FileName;
3124  UGME.second = new TPicture;
3125  UGME.second->LoadFromFile(UGME.first); // errors caught below
3126  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3127  {
3128  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3129  }
3130  UGI.UserGraphic = UGME.second;
3131  UGI.Width = UGI.UserGraphic->Width;
3132  UGI.Height = UGI.UserGraphic->Height;
3133  UserGraphicVectorAt(3, x) = UGI;
3134  }
3135  catch(const EInvalidGraphic &e) //non error catch
3136  {
3137  //message already sent in CheckUserGraphics
3138  FileError = true;
3139  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3140  if(!UserGraphicMap.empty())
3141  {
3142  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3143  {
3144  delete UGMIt->second;
3145  }
3146  UserGraphicMap.clear();
3147  }
3148  }
3149  catch(const Exception &e) //non error catch
3150  {
3151  //message already sent in CheckUserGraphics
3152  FileError = true;
3153  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3154  if(!UserGraphicMap.empty())
3155  {
3156  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3157  {
3158  delete UGMIt->second;
3159  }
3160  UserGraphicMap.clear();
3161  }
3162  }
3163  }
3164  }
3165  }
3166  Utilities->CallLogPop(2167);
3167 }
3168 
3169 // ---------------------------------------------------------------------------
3170 
3171 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3172 {
3173 // VecFile already open and its pointer at right place on calling
3174 // if GraphicsFollow true, then save Marker as **Active elements**1
3175 // save trackfinished flag
3176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3177  TTrackElement TrackElement, InactiveTrackElement;
3178 
3179 // save track elements
3180  Utilities->SaveFileInt(VecFile, TrackVector.size());
3181  if(GraphicsFollow)
3182  {
3183  VecFile << "**Active elements**1" << '\0' << '\n';
3184  }
3185  else
3186  {
3187  VecFile << "**Active elements**" << '\0' << '\n';
3188  }
3189  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3190  {
3191  TrackElement = TrackElementAt(1092, x);
3192  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3193  VecFile << TrackElement.SpeedTag << '\n';
3194  VecFile << TrackElement.HLoc << '\n';
3195  VecFile << TrackElement.VLoc << '\n';
3196  if(TrackElement.TrackType == GapJump)
3197  {
3198  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3199  VecFile << TrackElement.Conn[0] << '\n';
3200  }
3201  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3202  {
3203  VecFile << TrackElement.Attribute << '\n';
3204  }
3205  if(TrackElement.TrackType == SignalPost)
3206  {
3207  if(TrackElement.CallingOnSet)
3208  {
3209  VecFile << int(1) << '\n';
3210  }
3211  else
3212  {
3213  VecFile << int(0) << '\n';
3214  }
3215  }
3216  VecFile << TrackElement.Length01 << '\n';
3217  VecFile << TrackElement.Length23 << '\n';
3218  VecFile << TrackElement.SpeedLimit01 << '\n';
3219  VecFile << TrackElement.SpeedLimit23 << '\n';
3220  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3221  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3222 // new for v0.6
3223  if(TrackElement.TrackType == SignalPost)
3224  {
3225  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3226  {
3227  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3228  }
3229  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3230  {
3231  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3232  }
3233  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3234  {
3235  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3236  }
3237  else // 4 aspect
3238  {
3239  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3240  }
3241  }
3242  else
3243  {
3244  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3245  }
3246  }
3247 
3248  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3249  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3250  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3251  {
3252  InactiveTrackElement = InactiveTrackElementAt(136, x);
3253  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3254  VecFile << InactiveTrackElement.SpeedTag << '\n';
3255  VecFile << InactiveTrackElement.HLoc << '\n';
3256  VecFile << InactiveTrackElement.VLoc << '\n';
3257  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3258  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3259  }
3260  Utilities->CallLogPop(449);
3261 }
3262 
3263 // ---------------------------------------------------------------------------
3264 
3265 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3266 {
3267 // VecFile already open and its pointer at right place on calling
3268 // check trackfinished flag
3269 // inactive elements follow immediately after active elements, no need to check for a marker between them
3270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3271  int TempInt;
3272 
3273  GraphicsFollow = false;
3274  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3275  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3276  {
3277  Utilities->CallLogPop(1513);
3278  return(false);
3279  }
3280 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3281  AnsiString MarkerString;
3282 
3283  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3284  {
3285  Utilities->CallLogPop(1758);
3286  return(false);
3287  }
3288  if(MarkerString[MarkerString.Length()] == '1')
3289  {
3290  GraphicsFollow = true;
3291  }
3292  for(int x = 0; x < NumberOfActiveElements; x++)
3293  {
3294  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3295  {
3296  Utilities->CallLogPop(1759);
3297  return(false);
3298  }
3299  VecFile >> TempInt;
3300  int SpeedTag = TempInt;
3301  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3302  {
3303  Utilities->CallLogPop(1514);
3304  return(false);
3305  }
3306  VecFile >> TempInt;
3307  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3308  {
3309  Utilities->CallLogPop(1495);
3310  return(false);
3311  }
3312  VecFile >> TempInt;
3313  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3314  {
3315  Utilities->CallLogPop(1497);
3316  return(false);
3317  }
3318  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3319  {
3320  VecFile >> TempInt;
3321  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3322  {
3323  Utilities->CallLogPop(1499);
3324  return(false);
3325  }
3326  VecFile >> TempInt;
3327  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3328  {
3329  Utilities->CallLogPop(1500);
3330  return(false);
3331  }
3332  }
3333  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3334  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3335  {
3336  VecFile >> TempInt;
3337  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3338  {
3339  Utilities->CallLogPop(1502);
3340  return(false);
3341  }
3342  }
3343  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3344  {
3345  VecFile >> TempInt;
3346  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3347  {
3348  Utilities->CallLogPop(1155);
3349  return(false);
3350  }
3351  }
3352  VecFile >> TempInt;
3353  if((TempInt < -1) || (TempInt > 999999)) // Length01
3354  {
3355  Utilities->CallLogPop(1503);
3356  return(false);
3357  }
3358  VecFile >> TempInt;
3359  if((TempInt < -1) || (TempInt > 999999)) // Length23
3360  {
3361  Utilities->CallLogPop(1504);
3362  return(false);
3363  }
3364  VecFile >> TempInt;
3365  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3366  {
3367  Utilities->CallLogPop(1505);
3368  return(false);
3369  }
3370  VecFile >> TempInt;
3371  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3372  {
3373  Utilities->CallLogPop(1506);
3374  return(false);
3375  }
3376  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3377  {
3378  Utilities->CallLogPop(1142);
3379  return(false); // LocationName
3380  }
3381  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3382  {
3383  Utilities->CallLogPop(1143);
3384  return(false); // ActiveTrackElementName
3385  }
3386  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3387  {
3388  Utilities->CallLogPop(1787);
3389  return(false); // marker
3390  }
3391  }
3392  int NumberOfInactiveElements = 0;
3393 
3394  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3395  if(NumberOfInactiveElements < 0) // No of active elements
3396  {
3397  Utilities->CallLogPop(1493);
3398  return(false);
3399  }
3400  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3401  {
3402  Utilities->CallLogPop(1764);
3403  return(false); // **Inactive elements** marker
3404  }
3405  for(int x = 0; x < NumberOfInactiveElements; x++)
3406  {
3407  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3408  {
3409  Utilities->CallLogPop(1765);
3410  return(false);
3411  }
3412  VecFile >> TempInt;
3413  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3414  {
3415  Utilities->CallLogPop(1494);
3416  return(false);
3417  }
3418  VecFile >> TempInt;
3419  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3420  {
3421  Utilities->CallLogPop(1496);
3422  return(false);
3423  }
3424  VecFile >> TempInt;
3425  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3426  {
3427  Utilities->CallLogPop(1498);
3428  return(false);
3429  }
3430  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3431  {
3432  Utilities->CallLogPop(1144);
3433  return(false); // LocationName
3434  }
3435  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3436  {
3437  Utilities->CallLogPop(1788);
3438  return(false); // marker
3439  }
3440  }
3441  Utilities->CallLogPop(1507);
3442  return(true);
3443 }
3444 
3445 // ---------------------------------------------------------------------------
3446 
3447 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3448 {
3449  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3450  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3451 
3452  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3453  {
3454  Utilities->CallLogPop(2168);
3455  return(false);
3456  }
3457  // filename in Graphics folder, then HPos, then VPos
3458  AnsiString FileName = "", TempStr = "";
3459 
3460  for(int x = 0; x < NumberOfGraphics; x++)
3461  {
3462  TPicture *TempPicture = new TPicture;
3463  try
3464  {
3465  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3466  {
3467  Utilities->CallLogPop(2169);
3468  delete TempPicture;
3469  return(false);
3470  }
3471  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3472  delete TempPicture;
3473  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3474  {
3475  Utilities->CallLogPop(2170);
3476  return(false);
3477  }
3478  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3479  {
3480  Utilities->CallLogPop(2171);
3481  return(false);
3482  }
3483  }
3484  catch(const EInvalidGraphic &e) //non error catch
3485  {
3486  //move file pointer to end of graphic section for later checks in session files
3487  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3488  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3489  for(int y = x + 1; y < NumberOfGraphics; y++)
3490  {
3491  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3492  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3493  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3494  }
3495  ShowMessage(FileName +
3496  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3497  Utilities->CallLogPop(2172);
3498  delete TempPicture;
3499  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3500  }
3501  catch(const Exception &e) //non error catch
3502  {
3503  //move file pointer to end of graphic section for later checks in session files
3504  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3505  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3506  for(int y = x + 1; y < NumberOfGraphics; y++)
3507  {
3508  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3509  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3510  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3511  }
3512  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3513  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3514  Utilities->CallLogPop(2173);
3515  delete TempPicture;
3516  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3517  }
3518  }
3519  Utilities->CallLogPop(2174);
3520  return(true);
3521 }
3522 
3523 // ---------------------------------------------------------------------------
3524 
3525 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3526 {
3527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3528  int VecSize = Track->BarriersDownVector.size();
3529 
3530  Utilities->SaveFileInt(OutFile, VecSize);
3531  for(int x = 0; x < VecSize; x++)
3532  {
3534  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3535  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3536  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3537  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3538  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3539  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3540  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3541  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3542  }
3543  Utilities->CallLogPop(1963);
3544 }
3545 
3546 // ---------------------------------------------------------------------------
3547 
3548 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3549 {
3550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3551  int VecSize = Track->ChangingLCVector.size();
3552 
3553  Utilities->SaveFileInt(OutFile, VecSize);
3554  for(int x = 0; x < VecSize; x++)
3555  {
3557  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3558  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3559  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3560  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3561  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3562  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3563  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3564  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3565  }
3566  Utilities->CallLogPop(1980);
3567 }
3568 
3569 // ---------------------------------------------------------------------------
3570 
3571 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3572 {
3573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3574  int VecSize = Utilities->LoadFileInt(VecFile);
3575 
3576  for(int x = 0; x < VecSize; x++)
3577  {
3578  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3579  {
3580  Utilities->CallLogPop(1970);
3581  return(false);
3582  }
3583  if(!Utilities->CheckFileBool(VecFile))
3584  {
3585  Utilities->CallLogPop(1971);
3586  return(false);
3587  }
3588  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3589  {
3590  Utilities->CallLogPop(1972);
3591  return(false);
3592  }
3593  if(!Utilities->CheckFileDouble(VecFile))
3594  {
3595  Utilities->CallLogPop(1973);
3596  return(false);
3597  }
3598  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3599  {
3600  Utilities->CallLogPop(1974);
3601  return(false);
3602  }
3603  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3604  {
3605  Utilities->CallLogPop(1975);
3606  return(false);
3607  }
3608  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3609  {
3610  Utilities->CallLogPop(1976);
3611  return(false);
3612  }
3613  if(!Utilities->CheckFileDouble(VecFile))
3614  {
3615  Utilities->CallLogPop(1977);
3616  return(false);
3617  }
3618  }
3619  Utilities->CallLogPop(1978);
3620  return(true);
3621 }
3622 
3623 // ---------------------------------------------------------------------------
3624 
3625 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3626 {
3627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3628  int VecSize = Utilities->LoadFileInt(VecFile);
3629 
3630  for(int x = 0; x < VecSize; x++)
3631  {
3632  TActiveLevelCrossing TALC;
3633  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3634  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3635  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3636  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3637  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3638  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3639  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3640  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3641  BarriersDownVector.push_back(TALC);
3642  }
3643  Utilities->CallLogPop(1979);
3644 }
3645 
3646 // ---------------------------------------------------------------------------
3647 
3648 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3649 /*
3650  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3651  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3652  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3653 */
3654 {
3655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3656  TTrackElement Next;
3657 
3658 // Disp->ClearDisplay();
3660  while(ReturnNextInactiveTrackElement(0, Next))
3661  {
3662  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3663  {
3664  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3665  {
3666  // only plot if on screen, to save time
3667  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3669  {
3670  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3671  }
3672  }
3673  }
3674  }
3675 
3676  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3677 
3678  NextTrackElementPtr = TrackVector.begin();
3679  while(ReturnNextTrackElement(0, Next))
3680  {
3681  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3682  {
3683  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3685  {
3686  if(Next.TrackType == Points)
3687  {
3688  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3689  }
3690  else if(Next.TrackType == SignalPost)
3691  {
3692  PlotSignal(9, Next, Disp);
3693  }
3694  else if(Next.TrackType == GapJump)
3695  {
3696  PlotGap(0, Next, Disp);
3697  }
3698  else
3699  {
3700  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3701  }
3702  }
3703  }
3704  }
3705 
3706  if(BothPointFilletsAndBasicLCs)
3707  {
3709  while(ReturnNextInactiveTrackElement(4, Next))
3710  {
3711  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3712  {
3713  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3714  {
3715  // only plot if on screen, to save time, & OK as plotting one by one here
3716  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3718  {
3719  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3720  {
3721  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3722  }
3723  else
3724  {
3725  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3726  }
3727  }
3728  }
3729  }
3730  }
3731  }
3732  Disp->Update();
3733  Utilities->CallLogPop(468);
3734 }
3735 
3736 // ---------------------------------------------------------------------------
3737 
3738 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3739 {
3740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3741  if(UserGraphicVector.empty())
3742  {
3743  Utilities->CallLogPop(2175);
3744  return;
3745  }
3746  TUserGraphicItem UGI;
3747 
3748  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3749  {
3750  UGI = UserGraphicVectorAt(4, x);
3751  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3752  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3753  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3754  {
3755  Disp->PlotAndAddUserGraphic(0, UGI);
3756  }
3757  }
3758  Disp->Update();
3759  Utilities->CallLogPop(2176);
3760 }
3761 
3762 // ---------------------------------------------------------------------------
3763 
3764 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3765 /*
3766  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3767 */
3768 {
3769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3770 // need to change graphics back to black on white if have a dark background
3771  TColor OldTransparentColour = Utilities->clTransparent;
3772 
3774  {
3775  Utilities->clTransparent = TColor(0xFFFFFF); // white
3778  }
3779  TTrackElement Next;
3780 
3781  Bitmap->Canvas->CopyMode = cmSrcCopy;
3783  Graphics::TBitmap *GraphicOutput;
3784 
3785  while(ReturnNextInactiveTrackElement(2, Next))
3786  {
3787  GraphicOutput = Next.GraphicPtr;
3788  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3789  {
3790  if(Next.LocationName == "") // plot as named or unnamed (striped)
3791  {
3792  // default is not striped
3793  switch(Next.SpeedTag)
3794  {
3795  case 76: // t platform
3796  GraphicOutput = RailGraphics->gl76Striped;
3797  break;
3798 
3799  case 77: // h platform
3800  GraphicOutput = RailGraphics->bm77Striped;
3801  break;
3802 
3803  case 78: // v platform
3804  GraphicOutput = RailGraphics->bm78Striped;
3805  break;
3806 
3807  case 79: // r platform
3808  GraphicOutput = RailGraphics->gl79Striped;
3809  break;
3810 
3811  case 96: // concourse
3812  GraphicOutput = RailGraphics->ConcourseStriped;
3813  break;
3814 
3815  case 129: // v footbridge
3816  GraphicOutput = RailGraphics->gl129Striped;
3817  break;
3818 
3819  case 130: // h footbridge
3820  GraphicOutput = RailGraphics->gl130Striped;
3821  break;
3822 
3823  case 131: // non-station named loc
3824  GraphicOutput = RailGraphics->bmNameStriped;
3825  break;
3826 
3827  case 145: // v underpass
3828  GraphicOutput = RailGraphics->gl145Striped;
3829  break;
3830 
3831  case 146: // h underpass
3832  GraphicOutput = RailGraphics->gl146Striped;
3833  break;
3834 
3835  default:
3836  GraphicOutput = Next.GraphicPtr;
3837  break;
3838  }
3839  }
3840  if(Next.SpeedTag == 144) // level crossing
3841  {
3842  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3843  {
3844  GraphicOutput = RailGraphics->LCBothVer;
3845  }
3846  else
3847  {
3848  GraphicOutput = RailGraphics->LCBothHor;
3849  }
3850  }
3851  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3852  }
3853  }
3854 
3855  NextTrackElementPtr = TrackVector.begin();
3856  while(ReturnNextTrackElement(2, Next))
3857  {
3858  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3859  {
3860  if(Next.TrackType == Points) // plot both fillets
3861  {
3862  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3863  if(Next.SpeedTag < 28)
3864  {
3865  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3867  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3869  }
3870  else if(Next.SpeedTag < 132)
3871  {
3872  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3873  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3874  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3875  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3876  }
3877  else
3878  {
3879  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3880  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3881  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3882  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3883  }
3884  }
3885  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3886  {
3887  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3888  {
3889  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3890  }
3891  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3892  {
3893  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3894  }
3895  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3896  {
3897  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3898  }
3899  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3900  {
3901  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3902  }
3903  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3904  {
3905  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3906  }
3907  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3908  {
3909  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3910  }
3911  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3912  {
3913  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3914  }
3915  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3916  {
3917  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3918  }
3919  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3920  {
3921  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3922  }
3923  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3924  {
3925  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3926  }
3927  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3928  {
3929  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3930  }
3931  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3932  {
3933  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3934  }
3935  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3936  {
3937  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3938  }
3939  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3940  {
3941  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3942  }
3943  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3944  {
3945  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3946  }
3947  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3948  {
3949  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3950  }
3951  }
3952  // below added for version 0.6, only stop signals to be drawn
3953  else if(Next.TrackType == SignalPost)
3954  {
3955  for(int x = 0; x < 40; x++)
3956  {
3957  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3958  {
3959  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3960  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3961  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3962  int HOffset = 0;
3963  if(Next.SpeedTag > 73)
3964  {
3965  HOffset = 5;
3966  }
3967  else if(Next.SpeedTag == 71)
3968  {
3969  HOffset = 9;
3970  }
3971  int VOffset = 0;
3972  if(Next.SpeedTag == 69)
3973  {
3974  VOffset = 9;
3975  }
3976  else if(Next.SpeedTag == 72)
3977  {
3978  VOffset = 5;
3979  }
3980  else if(Next.SpeedTag == 74)
3981  {
3982  VOffset = 5;
3983  }
3984  Graphics::TBitmap *GraphicPtr;
3985  if(Next.SpeedTag > 71)
3986  {
3987  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3988  }
3989  else if(Next.SpeedTag < 70)
3990  {
3991  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3992  }
3993  else
3994  {
3995  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3996  }
3997  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3998  // plot special signal platform if present
3999  Graphics::TBitmap* SignalPlatformGraphic;
4000  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4001  {
4002  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4003  }
4004  // now plot signal (double yellow overwrites most of signal platform if present)
4005  // below amended for version 0.6
4007  {
4008  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4009  }
4010  else if(Next.SigAspect == TTrackElement::TwoAspect)
4011  {
4012  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4013  }
4014  else if(Next.SigAspect == TTrackElement::GroundSignal)
4015  {
4016  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4017  }
4018  else // 4 aspect
4019  {
4020  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4021  }
4022  break;
4023  }
4024  }
4025  }
4026  else
4027  {
4028  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4029  }
4030  }
4031  }
4032  if(OldTransparentColour != clB5G5R5)
4033  {
4034  Utilities->clTransparent = OldTransparentColour; // restore
4037  }
4038  Utilities->CallLogPop(1533);
4039 }
4040 
4041 // ---------------------------------------------------------------------------
4042 
4043 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4044 {
4045  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4046  if(UserGraphicVector.empty())
4047  {
4048  Utilities->CallLogPop(2192);
4049  return;
4050  }
4051  else
4052  {
4053  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4054  {
4055  Bitmap->Canvas->CopyMode = cmSrcCopy;
4056  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4057  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4058  }
4059  }
4060  Utilities->CallLogPop(2193);
4061 }
4062 
4063 // ---------------------------------------------------------------------------
4064 
4065 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
4066 /*
4067  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4068  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4069 */
4070 {
4071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
4072 // need to change graphics back to black on white if have a dark background
4073  TColor OldTransparentColour = Utilities->clTransparent;
4074 
4076  {
4077  Utilities->clTransparent = TColor(0xFFFFFF); // white
4080  }
4081  TTrackElement Next;
4082 
4083  Bitmap->Canvas->CopyMode = cmSrcCopy;
4085  Graphics::TBitmap *GraphicOutput;
4086 
4087  while(ReturnNextInactiveTrackElement(3, Next))
4088  {
4089  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4090  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4091  {
4092  if(Next.SpeedTag == 144) // level crossing
4093  {
4094  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4095  if(BaseElement == 1) // hor element
4096  {
4097  if(Next.Attribute == 1) // open to trains
4098  {
4099  GraphicOutput = RailGraphics->LCBothHor;
4100  }
4101  else // plot as closed to trains if in any other state
4102  {
4103  GraphicOutput = RailGraphics->LCBothVer;
4104  }
4105  }
4106  else // vert element
4107  {
4108  if(Next.Attribute == 1) // open to trains
4109  {
4110  GraphicOutput = RailGraphics->LCBothVer;
4111  }
4112  else // plot as closed to trains if in any other state
4113  {
4114  GraphicOutput = RailGraphics->LCBothHor;
4115  }
4116  }
4117  }
4118  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4119  }
4120  }
4121 
4122  NextTrackElementPtr = TrackVector.begin();
4123  while(ReturnNextTrackElement(3, Next))
4124  {
4125  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4126  {
4127  if(Next.TrackType == Points) // plot active fillet
4128  {
4129  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4130  if(Next.SpeedTag < 28)
4131  {
4132  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4134  }
4135  else if(Next.SpeedTag < 132)
4136  {
4137  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4139  }
4140  else
4141  {
4142  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4144  }
4145  }
4146  else if(Next.TrackType == GapJump) // plot as connected
4147  {
4148  if(Next.SpeedTag == 88)
4149  {
4150  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4151  }
4152  else if(Next.SpeedTag == 89)
4153  {
4154  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4155  }
4156  else if(Next.SpeedTag == 90)
4157  {
4158  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4159  }
4160  else if(Next.SpeedTag == 91)
4161  {
4162  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4163  }
4164  else if(Next.SpeedTag == 92)
4165  {
4166  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4167  }
4168  else if(Next.SpeedTag == 93)
4169  {
4170  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4171  }
4172  else if(Next.SpeedTag == 94)
4173  {
4174  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4175  }
4176  else if(Next.SpeedTag == 95)
4177  {
4178  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4179  }
4180  }
4181  else if(Next.TrackType == SignalPost) // plot in correct colour
4182  {
4183  for(int x = 0; x < 40; x++)
4184  {
4185  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4186  {
4187  // plot blank first, then plot platform if present - (always not striped for operating railway)
4188  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4189  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4190  int HOffset = 0;
4191  if(Next.SpeedTag > 73)
4192  {
4193  HOffset = 5;
4194  }
4195  else if(Next.SpeedTag == 71)
4196  {
4197  HOffset = 9;
4198  }
4199  int VOffset = 0;
4200  if(Next.SpeedTag == 69)
4201  {
4202  VOffset = 9;
4203  }
4204  else if(Next.SpeedTag == 72)
4205  {
4206  VOffset = 5;
4207  }
4208  else if(Next.SpeedTag == 74)
4209  {
4210  VOffset = 5;
4211  }
4212  Graphics::TBitmap *GraphicPtr;
4213  if(Next.SpeedTag > 71)
4214  {
4215  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4216  }
4217  else if(Next.SpeedTag < 70)
4218  {
4219  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4220  }
4221  else
4222  {
4223  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4224  }
4225  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4226  // plot special signal platform if present
4227  Graphics::TBitmap* SignalPlatformGraphic;
4228  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4229  {
4230  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4231  }
4232  // now plot signal (double yellow overwrites most of signal platform if present)
4233  // below amended for version 0.6
4235  {
4236  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4237  }
4238  else if(Next.SigAspect == TTrackElement::TwoAspect)
4239  {
4240  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4241  }
4242  else if(Next.SigAspect == TTrackElement::GroundSignal)
4243  {
4244  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4245  }
4246  else // 4 aspect
4247  {
4248  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4249  }
4250  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4251  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4252  {
4253  if(Next.SpeedTag == 68)
4254  {
4255  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4256  }
4257  if(Next.SpeedTag == 69)
4258  {
4259  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4260  }
4261  if(Next.SpeedTag == 70)
4262  {
4263  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4264  }
4265  if(Next.SpeedTag == 71)
4266  {
4267  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4268  }
4269  if(Next.SpeedTag == 72)
4270  {
4271  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4272  }
4273  if(Next.SpeedTag == 73)
4274  {
4275  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4276  }
4277  if(Next.SpeedTag == 74)
4278  {
4279  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4280  }
4281  if(Next.SpeedTag == 75)
4282  {
4283  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4284  }
4285  }
4286  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4287  {
4288  for(int x = 0; x < 40; x++)
4289  {
4290  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4291  {
4292  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4293  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4294  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4295  // plot special signal platform if present
4296  Graphics::TBitmap* SignalPlatformGraphic;
4297  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4298  {
4299  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4300  }
4301  // now plot signal
4302  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4303  break;
4304  }
4305  }
4306  }
4307  break;
4308  }
4309  }
4310  }
4311  else
4312  {
4313  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4314  }
4315  }
4316  }
4317  if(OldTransparentColour != clB5G5R5)
4318  {
4319  Utilities->clTransparent = OldTransparentColour; // restore
4322  }
4323  Utilities->CallLogPop(1701);
4324 }
4325 
4326 // ---------------------------------------------------------------------------
4327 
4328 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4329 {
4330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4331  for(unsigned int x = 0; x < TrackVector.size(); x++)
4332  {
4333  if(TrackElementAt(1093, x).TrackType == GapJump)
4334  {
4335  if(TrackElementAt(1094, x).Conn[0] > -1)
4336  {
4337  continue; // to next 'x' value as this element has already been set
4338  }
4339  // here if identify a GapJump element not yet set
4340  GapPos = x;
4341  GapHLoc = TrackElementAt(1095, x).HLoc;
4342  GapVLoc = TrackElementAt(1096, x).VLoc;
4343  // highlight it
4345  Utilities->CallLogPop(469);
4346  return(true);
4347  }
4348  }
4349  Utilities->CallLogPop(470);
4350  return(false);
4351 }
4352 
4353 // ---------------------------------------------------------------------------
4354 
4355 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4356 {
4357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4358  AnsiString(VLoc));
4359  int Position;
4360  TTrackElement TrackElement;
4361 
4362  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4363  {
4364  Utilities->CallLogPop(471);
4365  return(false); // not found
4366  }
4367  if(TrackElement.TrackType != GapJump)
4368  {
4369  Utilities->CallLogPop(472);
4370  return(false); // found something but not a gap
4371  }
4372  if(Position == GapPos)
4373  {
4374  Utilities->CallLogPop(473);
4375  return(false); // selected original gap
4376  }
4377  if(TrackElementAt(1097, Position).Conn[0] != -1)
4378  {
4379  Utilities->CallLogPop(474);
4380  return(false); // already selected
4381  }
4382  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4383  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4384  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4385  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4386 // now highlight the selected location
4387  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4388  Utilities->CallLogPop(475);
4389  return(true);
4390 }
4391 
4392 // ---------------------------------------------------------------------------
4393 
4394 bool TTrack::GapsUnset(int Caller)
4395 // returns true if there are gaps and any are unset
4396 {
4397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4398  if(TrackVector.size() == 0)
4399  {
4400  Utilities->CallLogPop(476);
4401  return(false);
4402  }
4403  for(unsigned int x = 0; x < TrackVector.size(); x++)
4404  {
4405  if(TrackElementAt(1102, x).TrackType == GapJump)
4406  {
4407  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4408  {
4409  Utilities->CallLogPop(477);
4410  return(true);
4411  }
4412  else // set, but may not have matching element, or that element may not be set
4413  {
4414  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4415  // check that the element pointed to by the gap link is a GapJump
4416  {
4417  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4418  Utilities->CallLogPop(1137);
4419  return(false);
4420  }
4421 // here if gap connection is itself a GapJump
4422  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4423  // check that the element pointed to by the gap link is a GapJump & that its gap link
4424  // points back to 'x'
4425  {
4426  Utilities->CallLogPop(478);
4427  return(true);
4428  }
4429 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4430  }
4431  } // if(TrackElementAt(, x).TrackType == GapJump)
4432 
4433  } // for x...
4434  Utilities->CallLogPop(479);
4435  return(false);
4436 }
4437 
4438 // ---------------------------------------------------------------------------
4439 
4440 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4441 {
4442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4443  for(unsigned int x = 0; x < TrackVector.size(); x++)
4444  {
4445  if(TrackElementAt(1110, x).TrackType == GapJump)
4446  {
4447  Utilities->CallLogPop(1105);
4448  return(false);
4449  }
4450  }
4451  Utilities->CallLogPop(1106);
4452  return(true);
4453 }
4454 
4455 // ---------------------------------------------------------------------------
4456 
4457 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4458 {
4459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4460  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4461  {
4462  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4463  {
4464  Utilities->CallLogPop(1107);
4465  return(false);
4466  }
4467  }
4468  for(unsigned int x = 0; x < TrackVector.size(); x++)
4469  {
4470  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4471  {
4472  Utilities->CallLogPop(1108);
4473  return(false);
4474  }
4475  }
4476  Utilities->CallLogPop(1109);
4477  return(true);
4478 }
4479 
4480 // ---------------------------------------------------------------------------
4481 
4483 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4484 // returns false otherwise or if there are no NamedLocationElements
4485 {
4486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4487  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4488  {
4489  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4490  {
4491  if(InactiveTrackElementAt(139, x).LocationName == "")
4492  {
4493  Utilities->CallLogPop(1110);
4494  return(true);
4495  }
4496  }
4497  }
4498  for(unsigned int x = 0; x < TrackVector.size(); x++)
4499  {
4500  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4501  {
4502  if(TrackElementAt(1113, x).LocationName == "")
4503  {
4504  Utilities->CallLogPop(1111);
4505  return(true);
4506  }
4507  }
4508  }
4509  Utilities->CallLogPop(1112);
4510  return(false);
4511 }
4512 
4513 // ---------------------------------------------------------------------------
4514 
4515 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4516 {
4517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4518  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4519  Utilities->CallLogPop(480);
4520 }
4521 
4522 // ---------------------------------------------------------------------------
4523 
4525 {
4526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4527  if(TrackVector.size() == 0)
4528  {
4529  Utilities->CallLogPop(481);
4530  return;
4531  }
4532  for(unsigned int x = 0; x < TrackVector.size(); x++)
4533  {
4534  if(TrackElementAt(1114, x).TrackType == GapJump)
4535  {
4536  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4537  {
4538  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4539  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4540  {
4541  TrackElementAt(1118, x).Conn[0] = -1;
4542  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4543  continue; // to next 'x'
4544  }
4545 // here if gap connection is itself a GapJump
4546  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4547  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4548  // if not clear Conns & CLks
4549  {
4550  TrackElementAt(1121, x).Conn[0] = -1;
4551  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4552  continue; // to next 'x'
4553  }
4554 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4555 // hence no more action needed on these Conns & CLks
4556  }
4557  } // else //gap jump
4558 
4559  } // for x...
4560 // throw Exception("Test Exception");//test
4561  Utilities->CallLogPop(482);
4562 }
4563 
4564 // ---------------------------------------------------------------------------
4565 
4566 void TTrack::ResetSignals(int Caller)
4567 {
4568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4569  for(unsigned int x = 0; x < TrackVector.size(); x++)
4570  {
4571  if(TrackElementAt(1123, x).TrackType == SignalPost)
4572  {
4573  TrackElementAt(1124, x).Attribute = 0;
4574  }
4575  }
4576  Utilities->CallLogPop(483);
4577 }
4578 
4579 // ---------------------------------------------------------------------------
4580 
4581 void TTrack::ResetPoints(int Caller)
4582 {
4583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4584  for(unsigned int x = 0; x < TrackVector.size(); x++)
4585  {
4586  if(TrackElementAt(1125, x).TrackType == Points)
4587  {
4588  TrackElementAt(1126, x).Attribute = 0;
4589  }
4590  }
4591  Utilities->CallLogPop(484);
4592 }
4593 
4594 // ---------------------------------------------------------------------------
4595 
4596 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4597 {
4598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4599  if(TrackVector.empty())
4600  {
4601  TrackMap.clear();
4602  Utilities->CallLogPop(485);
4603  return(true);
4604  }
4605 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4606  THVPair TrackMapKeyPair;
4607 
4608  NewVector.clear();
4609  TTrackMapIterator TrackMapPtr;
4610 
4611  if(!TrackMap.empty())
4612  {
4613  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4614  {
4615  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4616  }
4617  }
4618  if(NewVector.size() != TrackMap.size())
4619  {
4620  throw Exception("Error - Map & Vector different sizes");
4621  }
4622  unsigned int NonZeroCount = 0;
4623 
4624  for(unsigned int x = 0; x < TrackVector.size(); x++)
4625  {
4626  if(TrackElementAt(1127, x).TrackType != Erase)
4627  {
4628  NonZeroCount++;
4629  }
4630  }
4631  if(NewVector.size() != NonZeroCount)
4632  {
4633  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4634  }
4636  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4637  TTrackMapEntry TrackMapEntry;
4638 
4639  for(unsigned int x = 0; x < TrackVector.size(); x++)
4640  {
4641  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4642  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4643  TrackMapEntry.first = TrackMapKeyPair;
4644  TrackMapEntry.second = x;
4645  if(!(TrackMap.insert(TrackMapEntry).second))
4646  {
4647  throw Exception("Error - map insertion failure, TrackVector in error");
4648  }
4649  }
4650 // All track now relocated in TrackVector, reset all Conns & CLks
4651  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4652  {
4653  for(unsigned int y = 0; y < 4; y++)
4654  {
4655  TrackElementAt(1130, x).Conn[y] = -1;
4656  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4657  }
4658  }
4659  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4660  CheckMapAndTrack(4); // test
4661  CheckMapAndInactiveTrack(4); // test
4662  CheckLocationNameMultiMap(8); // test
4663  if(!ResetGapsFromGapMap(1))
4664  {
4665  Utilities->CallLogPop(489);
4666  return(false);
4667  }
4668  Utilities->CallLogPop(490);
4669  return(true);
4670 }
4671 
4672 // ---------------------------------------------------------------------------
4673 
4674 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4675 {
4676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4677  GapMap.clear();
4678  THVPair GapMapKeyPair, GapMapValuePair;
4679  TGapMapEntry GapMapEntry;
4680 
4681  for(unsigned int x = 0; x < TrackVector.size(); x++)
4682  {
4683  if(TrackElementAt(1132, x).TrackType == GapJump)
4684  {
4685  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4686  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4687  GapMapEntry.first = GapMapKeyPair;
4688  if(TrackElementAt(1135, x).Conn[0] == -1)
4689  {
4690  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4691  }
4692  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4693  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4694  GapMapEntry.second = GapMapValuePair;
4695  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4696  {
4697  GapMap.insert(GapMapEntry);
4698  }
4699  }
4700  }
4701  Utilities->CallLogPop(492);
4702 }
4703 
4704 // ---------------------------------------------------------------------------
4705 
4706 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4707 {
4708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4709  LocError = false;
4710  bool CheckForLinks = false;
4711 
4712  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4713  {
4714  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4715  {
4716  continue; // skip blank elements
4717  }
4718 // check footcrossing linkages
4719  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4720  {
4721  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4722  {
4723  ShowMessage(
4724  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4725  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4726  "can't connect to an underpass or vice versa)");
4727  HLoc = TrackElementAt(1141, x).HLoc;
4728  VLoc = TrackElementAt(1142, x).VLoc;
4729  LocError = true;
4730  Utilities->CallLogPop(493);
4731  return(false);
4732  }
4733  }
4734  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4735  {
4736  CheckForLinks = false;
4737  if(TrackElementAt(1143, x).Link[y] <= 0)
4738  {
4739  continue; // no link
4740  }
4741  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4742  {
4743  continue; // buffer
4744  }
4745  if(TrackElementAt(1146, x).Config[y] == Gap)
4746  {
4747  continue; // gaps set later from GapMap
4748 
4749  }
4750  // get required H & V for track element joining link 'y'
4751  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4752  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4753  // find track element if present
4754  bool ConnectionFoundFlag;
4755  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4756  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4757  {
4758  ShowMessage("Can't have a track element adjacent to a continuation exit");
4759  HLoc = TrackElementAt(1152, x).HLoc;
4760  VLoc = TrackElementAt(1153, x).VLoc;
4761  LocError = true;
4762  if(FinalCall)
4763  {
4764  throw Exception("Error in final track linkage - continuation adjacent to another element");
4765  }
4766  Utilities->CallLogPop(1539);
4767  return(false);
4768  }
4769  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4770  {
4771  continue;
4772  }
4773  if(ConnectionFoundFlag)
4774  {
4775  TrackElementAt(1156, x).Conn[y] = VecPos;
4776  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4777  bool LinkFoundFlag = false;
4778  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4779  {
4780  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4781  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4782  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4783  }
4784  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4785  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4786  {
4787  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4788  // need room for a train (2 elements) without fouling points or signals
4789  }
4790  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4791  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4792  {
4793  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4794  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4795  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4796  // be named but needs the adjacent element named too
4797  }
4798  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4799  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4800  {
4801  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4802  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4803  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4804  }
4805  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4806  {
4807  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4808  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4809  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4810  }
4811  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4812  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4813  {
4814  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4815  }
4816  else
4817  {
4818  CheckForLinks = true;
4819  }
4820  if(CheckForLinks)
4821  {
4822  for(unsigned int a = 0; a < 4; a++)
4823  {
4824  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
4825  (TrackElementAt(1181, VecPos).Config[a] != Gap))
4826  {
4827  TrackElementAt(1182, x).ConnLinkPos[y] = a;
4828  // note - this ensures that if the connecting element is a leading point
4829  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4830  // (Points have the same link value for both [0] and [2])
4831  LinkFoundFlag = true;
4832  break; // stop after first find or will find later link for leading point
4833  }
4834  }
4835  }
4836  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4837  if(!LinkFoundFlag)
4838  {
4839  HLoc = TrackElementAt(1183, x).HLoc;
4840  VLoc = TrackElementAt(1184, x).VLoc;
4841  LocError = true;
4842  if(FinalCall)
4843  {
4844  throw Exception("Error in final track linkage - invalid link");
4845  }
4846  Utilities->CallLogPop(494);
4847  return(false);
4848  }
4849  }
4850  // if there isn't a connection set the invert values for the offending element
4851  else // if(ConnectionFoundFlag)
4852  {
4853  HLoc = TrackElementAt(1185, x).HLoc;
4854  VLoc = TrackElementAt(1186, x).VLoc;
4855  LocError = true;
4856  if(FinalCall)
4857  {
4858  throw Exception("Error in final track linkage - connection not found");
4859  }
4860  Utilities->CallLogPop(495);
4861  return(false);
4862  }
4863  }
4864  } // for(unsigned int x=0;x<TrackVector.size();x++)
4865 
4866  if(FinalCall)
4867  {
4869  }
4870 // final check
4871  bool ConnErrorFlag = false;
4872 
4873  for(unsigned int x = 0; x < TrackVector.size(); x++)
4874  {
4875  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
4876  {
4877  ConnErrorFlag = true;
4878  }
4879  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
4880  {
4881  ConnErrorFlag = true;
4882  }
4883  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
4884  {
4885  ConnErrorFlag = true;
4886  }
4887  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
4888  {
4889  ConnErrorFlag = true;
4890  }
4891  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4892  {
4893  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
4894  {
4895  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
4896  {
4897  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4898  }
4899  }
4900  }
4901  }
4902  if(ConnErrorFlag)
4903  {
4904  if(FinalCall)
4905  {
4906  throw Exception("ConnError in LinkTrack - Final");
4907  }
4908  else
4909  {
4910  throw Exception("ConnError in LinkTrack - Precheck");
4911  }
4912  }
4913  bool CLkErrorFlag = false;
4914 
4915  for(unsigned int x = 0; x < TrackVector.size(); x++)
4916  {
4917  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
4918  {
4919  CLkErrorFlag = true;
4920  }
4921  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
4922  {
4923  CLkErrorFlag = true;
4924  }
4925  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
4926  {
4927  CLkErrorFlag = true;
4928  }
4929  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
4930  {
4931  CLkErrorFlag = true;
4932  }
4933  }
4934 
4935  if(CLkErrorFlag)
4936  {
4937  if(FinalCall)
4938  {
4939  throw Exception("CLkError in LinkTrack - Final");
4940  }
4941  else
4942  {
4943  throw Exception("CLkError in LinkTrack - Precheck");
4944  }
4945  }
4946 // set element lengths to min of 20m
4947  for(unsigned int x = 0; x < TrackVector.size(); x++)
4948  {
4949  if(TrackElementAt(1214, x).TrackType == Erase)
4950  {
4951  continue; // skip blank elements
4952  }
4953  if(TrackElementAt(1215, x).Length01 < 20)
4954  {
4955  TrackElementAt(1216, x).Length01 = 20;
4956  }
4957  if((TrackElementAt(1217, x).Length23 < 20) && (TrackElementAt(1218, x).Length23 != -1))
4958  {
4959  TrackElementAt(1219, x).Length23 = 20;
4960  }
4961  }
4962 
4963  if(FinalCall) // ONLY at FinalCall, no point calling twice
4964  {
4965  CalcHLocMinEtc(3);
4966  }
4967 
4968  Utilities->CallLogPop(497);
4969  return(true);
4970 }
4971 
4972 // ---------------------------------------------------------------------------
4973 
4974 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4975 {
4976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4977  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4978  {
4979  if(TrackElementAt(1220, x).TrackType == Erase)
4980  {
4981  continue; // skip blank elements
4982 
4983  }
4984 // check footcrossing linkages
4985  if(TrackElementAt(1221, x).TrackType == FootCrossing)
4986  {
4987  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
4988  {
4989  Utilities->CallLogPop(1127);
4990  return(false);
4991  }
4992  }
4993  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4994  {
4995  if(TrackElementAt(1223, x).Link[y] <= 0)
4996  {
4997  continue; // no link
4998  }
4999  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5000  {
5001  continue; // buffer
5002  }
5003  if(TrackElementAt(1226, x).Config[y] == Gap)
5004  {
5005  continue; // gaps set later from GapMap
5006 
5007  }
5008  // get required H & V for track element joining link 'y'
5009  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5010  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5011  // find track element if present
5012  bool ConnectionFoundFlag;
5013  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5014  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5015  {
5016  if(FinalCall)
5017  {
5018  throw Exception("Error in final track linkage - continuation adjacent to another element");
5019  }
5020  Utilities->CallLogPop(1540);
5021  return(false);
5022  }
5023  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5024  {
5025  continue;
5026  }
5027  if(ConnectionFoundFlag)
5028  {
5029  TrackElementAt(1234, x).Conn[y] = VecPos;
5030  bool LinkFoundFlag = false;
5031  // find connecting link in the newly found track element if there is one & make checks
5032  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5033  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5034  {
5035  Utilities->CallLogPop(1541);
5036  return(false);
5037  }
5038  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5039  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5040  {
5041  Utilities->CallLogPop(1542);
5042  return(false);
5043  }
5044  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5045  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5046  {
5047  Utilities->CallLogPop(1543);
5048  return(false);
5049  }
5050  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5051  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5052  {
5053  Utilities->CallLogPop(1981);
5054  return(false);
5055  }
5056 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5057  else if(TrackElementAt(, x).TrackType == Continuation)
5058  {
5059  int H = TrackElementAt(, x).HLoc;
5060  int V = TrackElementAt(, x).VLoc;
5061  bool FoundFlag = false;
5062  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5063  if(FoundFlag)
5064  {
5065  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5066  {
5067  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5068  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5069  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5070  if(FoundFlag)
5071  {
5072  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5073  {
5074  Utilities->CallLogPop();
5075  return false;
5076  }
5077  }
5078  else
5079  {
5080  Utilities->CallLogPop();
5081  return false;
5082  }
5083  }
5084  }
5085  }
5086 */
5087  for(unsigned int a = 0; a < 4; a++)
5088  {
5089  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5090  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5091  {
5092  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5093  // note - this ensures that if the connecting element is a leading point
5094  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5095  // (Points have the same link value for both [0] and [2])
5096  LinkFoundFlag = true;
5097  break; // stop after first find or will find later link for leading point
5098  }
5099  }
5100  if(!LinkFoundFlag)
5101  {
5102  if(FinalCall)
5103  {
5104  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5105  }
5106  Utilities->CallLogPop(1128);
5107  return(false);
5108  }
5109  }
5110  else // if(ConnectionFoundFlag)
5111  {
5112  if(FinalCall)
5113  {
5114  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5115  }
5116  Utilities->CallLogPop(1129);
5117  return(false);
5118  }
5119  }
5120  } // for(unsigned int x=0;x<TrackVector.size();x++)
5121 
5122  if(FinalCall)
5123  {
5125  }
5126 // final check
5127  bool ConnErrorFlag = false;
5128 
5129  for(unsigned int x = 0; x < TrackVector.size(); x++)
5130  {
5131  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5132  {
5133  ConnErrorFlag = true;
5134  }
5135  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5136  {
5137  ConnErrorFlag = true;
5138  }
5139  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5140  {
5141  ConnErrorFlag = true;
5142  }
5143  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5144  {
5145  ConnErrorFlag = true;
5146  }
5147  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5148  {
5149  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5150  {
5151  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5152  {
5153  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5154  }
5155  }
5156  }
5157  }
5158  if(ConnErrorFlag)
5159  {
5160  if(FinalCall)
5161  {
5162  throw Exception("ConnError in LinkTrack - Final");
5163  }
5164  else
5165  {
5166  throw Exception("ConnError in LinkTrack - Precheck");
5167  }
5168  }
5169  bool CLkErrorFlag = false;
5170 
5171  for(unsigned int x = 0; x < TrackVector.size(); x++)
5172  {
5173  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5174  {
5175  CLkErrorFlag = true;
5176  }
5177  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5178  {
5179  CLkErrorFlag = true;
5180  }
5181  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5182  {
5183  CLkErrorFlag = true;
5184  }
5185  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5186  {
5187  CLkErrorFlag = true;
5188  }
5189  }
5190 
5191  if(CLkErrorFlag)
5192  {
5193  if(FinalCall)
5194  {
5195  throw Exception("CLkError in LinkTrack - Final");
5196  }
5197  else
5198  {
5199  throw Exception("CLkError in LinkTrack - Precheck");
5200  }
5201  }
5202 // set element lengths to min of 20m
5203  for(unsigned int x = 0; x < TrackVector.size(); x++)
5204  {
5205  if(TrackElementAt(1284, x).TrackType == Erase)
5206  {
5207  continue; // skip blank elements
5208  }
5209  if(TrackElementAt(1285, x).Length01 < 20)
5210  {
5211  TrackElementAt(1286, x).Length01 = 20;
5212  }
5213  if((TrackElementAt(1287, x).Length23 < 20) && (TrackElementAt(1288, x).Length23 != -1))
5214  {
5215  TrackElementAt(1289, x).Length23 = 20;
5216  }
5217  }
5218 
5219  if(FinalCall) // ONLY at FinalCall, no point calling twice
5220  {
5221  CalcHLocMinEtc(7);
5222  }
5223  Utilities->CallLogPop(1130);
5224  return(true);
5225 }
5226 
5227 // ---------------------------------------------------------------------------
5228 
5229 bool TTrack::IsTrackLinked(int Caller) // not used any more
5230 {
5231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5232  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5233  {
5234  if(TrackElementAt(1290, x).TrackType == Erase)
5235  {
5236  Utilities->CallLogPop(498);
5237  return(false);
5238  }
5239 // check foot linkages
5240  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5241  {
5242  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5243  {
5244  Utilities->CallLogPop(499);
5245  return(false);
5246  }
5247  }
5248  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5249  {
5250  if(TrackElementAt(1293, x).Link[y] <= 0)
5251  {
5252  continue; // no link
5253  }
5254  if(TrackElementAt(1294, x).Config[y] == End)
5255  {
5256  continue; // buffer or continuation
5257  }
5258  if(TrackElementAt(1295, x).Config[y] == Gap)
5259  {
5260  continue; // gaps set later from GapMap
5261 
5262  }
5263  // get required H & V for track element joining link 'y'
5264  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5265  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5266  // find track element if present
5267  bool ConnectionFoundFlag = false;
5268  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5269  if(ConnectionFoundFlag)
5270  {
5271  TrackElementAt(1300, x).Conn[y] = VecPos;
5272  // find connecting link in the newly found track element if there is one & make buffer check
5273  bool LinkFoundFlag = false;
5274  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5275  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5276  {
5277  Utilities->CallLogPop(500);
5278  return(false);
5279  }
5280  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5281  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5282  {
5283  Utilities->CallLogPop(501);
5284  return(false);
5285  }
5286  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5287  {
5288  Utilities->CallLogPop(502);
5289  return(false);
5290  }
5291  else
5292  {
5293  for(unsigned int a = 0; a < 4; a++)
5294  {
5295  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5296  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5297  {
5298  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5299  // note - this ensures that if the connecting element is a leading point
5300  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5301  // (Points have the same link value for both [0] and [2])
5302  LinkFoundFlag = true;
5303  break; // stop after first find or will find later link for leading point
5304  }
5305  }
5306  }
5307  if(!LinkFoundFlag)
5308  {
5309  Utilities->CallLogPop(503);
5310  return(false);
5311  }
5312  }
5313  else // if(ConnectionFoundFlag)
5314  {
5315  Utilities->CallLogPop(504);
5316  return(false);
5317  }
5318  }
5319  } // for(unsigned int x=0;x<TrackVector.size();x++)
5320 
5321 // final check
5322  bool ConnErrorFlag = false;
5323 
5324  for(unsigned int x = 0; x < TrackVector.size(); x++)
5325  {
5326  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5327  {
5328  ConnErrorFlag = true;
5329  }
5330  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5331  {
5332  ConnErrorFlag = true;
5333  }
5334  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5335  {
5336  ConnErrorFlag = true;
5337  }
5338  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5339  {
5340  ConnErrorFlag = true;
5341  }
5342  }
5343  if(ConnErrorFlag)
5344  {
5345  Utilities->CallLogPop(505);
5346  return(false);
5347  }
5348  bool CLkErrorFlag = false;
5349 
5350  for(unsigned int x = 0; x < TrackVector.size(); x++)
5351  {
5352  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5353  {
5354  CLkErrorFlag = true;
5355  }
5356  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5357  {
5358  CLkErrorFlag = true;
5359  }
5360  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5361  {
5362  CLkErrorFlag = true;
5363  }
5364  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5365  {
5366  CLkErrorFlag = true;
5367  }
5368  }
5369 
5370  if(CLkErrorFlag)
5371  {
5372  Utilities->CallLogPop(506);
5373  return(false);
5374  }
5375  Utilities->CallLogPop(507);
5376  return(true);
5377 }
5378 
5379 // ---------------------------------------------------------------------------
5380 
5382 {
5383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5384  int Position1, Position2;
5385  TTrackElement TrackElement1, TrackElement2;
5386  TGapMapIterator GapMapPtr;
5387 
5388  if(!GapMap.empty())
5389  {
5390  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5391  {
5392  int HLoc1 = GapMapPtr->first.first;
5393  int VLoc1 = GapMapPtr->first.second;
5394  int HLoc2 = GapMapPtr->second.first;
5395  int VLoc2 = GapMapPtr->second.second;
5396  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5397  {
5398  throw Exception("Failed to find H & V for gap1, GapMap in error");
5399  }
5400  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5401  {
5402  throw Exception("Failed to find H & V for gap2, GapMap in error");
5403  }
5404  if(TrackElementAt(9, Position1).TrackType != GapJump)
5405  {
5406  throw Exception("Element at Pos1 not a gap, GapMap in error");
5407  }
5408  if(TrackElementAt(10, Position2).TrackType != GapJump)
5409  {
5410  throw Exception("Element at Pos2 not a gap, GapMap in error");
5411  }
5412  TrackElementAt(11, Position1).Conn[0] = Position2;
5413  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5414  TrackElementAt(13, Position2).Conn[0] = Position1;
5415  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5416  }
5417  }
5418  Utilities->CallLogPop(510);
5419  return(true);
5420 }
5421 
5422 // ---------------------------------------------------------------------------
5423 
5424 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5425 {
5426 // TIMPair MapEntry;
5427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5428  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5429  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5430  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5431  TLocationNameMultiMapEntry LocationNameEntry;
5432 
5433  LocationNameEntry.first = TrackElement.LocationName;
5434  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5435  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5436  {
5437 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5438 // could arise when loading old railways with multiple NonStationNamedLocs
5439  bool FoundFlag = false;
5440  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5441  if(FoundFlag)
5442  {
5443  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5444  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5445  {
5446  Utilities->CallLogPop(1813);
5447  return;
5448  }
5449  }
5450  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5451  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5452  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5453  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5454  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5455  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5456  if(TrackElement.FixedNamedLocationElement)
5457  {
5458  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5459  LocationNameMultiMap.insert(LocationNameEntry);
5460  }
5461  if(TrackElement.HLoc < HLocMin)
5462  {
5463  HLocMin = TrackElement.HLoc;
5464  }
5465  if(TrackElement.HLoc > HLocMax)
5466  {
5467  HLocMax = TrackElement.HLoc;
5468  }
5469  if(TrackElement.VLoc < VLocMin)
5470  {
5471  VLocMin = TrackElement.VLoc;
5472  }
5473  if(TrackElement.VLoc > VLocMax)
5474  {
5475  VLocMax = TrackElement.VLoc;
5476  }
5477  }
5478  else
5479  {
5480 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5481 // shouldn't arise but leave in as a safeguard
5482  bool FoundFlag = false;
5483  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5484  if(FoundFlag)
5485  {
5486  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5487  {
5488  Utilities->CallLogPop(1814);
5489  return;
5490  }
5491  }
5492  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5493  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5494  {
5495  TrackMapKeyPair.first = TrackElement.HLoc;
5496  TrackMapKeyPair.second = TrackElement.VLoc;
5497  TrackMapEntry.first = TrackMapKeyPair;
5498  TrackMapEntry.second = TrackVector.size() - 1;
5499  TrackMap.insert(TrackMapEntry);
5500  if(TrackElement.FixedNamedLocationElement)
5501  {
5502  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5503  LocationNameMultiMap.insert(LocationNameEntry);
5504  }
5505  if(TrackElement.HLoc < HLocMin)
5506  {
5507  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5508  }
5509  if(TrackElement.HLoc > HLocMax)
5510  {
5511  HLocMax = TrackElement.HLoc;
5512  }
5513  if(TrackElement.VLoc < VLocMin)
5514  {
5515  VLocMin = TrackElement.VLoc;
5516  }
5517  if(TrackElement.VLoc > VLocMax)
5518  {
5519  VLocMax = TrackElement.VLoc;
5520  }
5521  }
5522  }
5523 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5524 // CheckMapAndInactiveTrack(6);//test
5525 
5526 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5527 // with the Platforms until layout fully loaded
5528  Utilities->CallLogPop(511);
5529 }
5530 
5531 // ---------------------------------------------------------------------------
5532 
5533 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5534 {
5535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5536  AnsiString(VLoc));
5537  THVPair TrackMapKeyPair;
5538 
5539  FoundFlag = false;
5540  TTrackMapIterator TrackMapPtr;
5541 
5542  TrackMapKeyPair.first = HLoc;
5543  TrackMapKeyPair.second = VLoc;
5544  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5545  if(TrackMapPtr == TrackMap.end())
5546  {
5547  Utilities->CallLogPop(512);
5548  return(-1); // nothing found
5549  }
5550  else
5551  {
5552  FoundFlag = true;
5553  Utilities->CallLogPop(513);
5554  return(TrackMapPtr->second);
5555  }
5556 }
5557 
5558 // ---------------------------------------------------------------------------
5559 
5560 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5561 {
5562  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5563  AnsiString(VLoc));
5564  THVPair TrackMapKeyPair;
5565  TTrackMapIterator TrackMapPtr;
5566 
5567  TrackMapKeyPair.first = HLoc;
5568  TrackMapKeyPair.second = VLoc;
5569  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5570  if(TrackMapPtr == TrackMap.end())
5571  {
5572  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5573  throw Exception(Message);
5574  }
5575  else
5576  {
5577  Utilities->CallLogPop(1943);
5578  return(TrackElementAt(871, TrackMapPtr->second));
5579  }
5580 }
5581 
5582 // ---------------------------------------------------------------------------
5583 
5584 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5585 { //modded at v2.9.2 to make Map & Vector references
5586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5587  AnsiString(VLoc));
5588  THVPair MapKeyPair;
5589  TTrackMapIterator MapPtr;
5590 
5591  MapKeyPair.first = HLoc;
5592  MapKeyPair.second = VLoc;
5593  MapPtr = Map.find(MapKeyPair);
5594  if(MapPtr == Map.end())
5595  {
5596  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5597  throw Exception(Message);
5598  }
5599  else
5600  {
5601  Utilities->CallLogPop(2280);
5602  return(Vector.at(MapPtr->second));
5603  }
5604 }
5605 
5606 // ---------------------------------------------------------------------------
5607 
5609 {
5610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5611  AnsiString(VLoc));
5612  THVPair InactiveTrackMapKeyPair;
5613  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5614 
5615  InactiveTrackMapKeyPair.first = HLoc;
5616  InactiveTrackMapKeyPair.second = VLoc;
5617  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5618  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5619  {
5620  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5621  throw Exception(Message);
5622  }
5623  else
5624  {
5625  Utilities->CallLogPop(1949);
5626  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5627  }
5628 }
5629 
5630 // ---------------------------------------------------------------------------
5631 
5632 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5633 {
5634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5635  bool Present = true;
5636  THVPair TrackMapKeyPair;
5637  TTrackMapIterator TrackMapPtr;
5638 
5639  TrackMapKeyPair.first = HLoc;
5640  TrackMapKeyPair.second = VLoc;
5641  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5642  if(TrackMapPtr == TrackMap.end())
5643  {
5644  Present = false;
5645  }
5646  Utilities->CallLogPop(2057);
5647  return(Present);
5648 }
5649 
5650 // ---------------------------------------------------------------------------
5651 
5652 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5653 {
5654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5655  AnsiString(VLoc));
5656  bool Present = true;
5657  THVPair InactiveTrackMapKeyPair;
5658  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5659 
5660  InactiveTrackMapKeyPair.first = HLoc;
5661  InactiveTrackMapKeyPair.second = VLoc;
5662  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5663  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5664  {
5665  Present = false;
5666  }
5667  Utilities->CallLogPop(2058);
5668  return(Present);
5669 }
5670 
5671 // ---------------------------------------------------------------------------
5672 
5673 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5674 // max number of elements is 2, for platforms
5675 // note that both elements of RetPair may be the same, if only one present in map
5676 {
5677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5678  AnsiString(VLoc));
5679  THVPair InactiveTrackMapKeyPair;
5680  TIMPair RetPair;
5681  TInactiveTrackRange InactiveTrackRange;
5682 
5683  FoundFlag = false;
5684  InactiveTrackMapKeyPair.first = HLoc;
5685  InactiveTrackMapKeyPair.second = VLoc;
5686  if(InactiveTrack2MultiMap.empty())
5687  {
5688  RetPair.first = 0;
5689  RetPair.second = 0;
5690  Utilities->CallLogPop(1815);
5691  return(RetPair); // map empty
5692  }
5693  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5694  if(InactiveTrackRange.first == InactiveTrackRange.second)
5695  {
5696  RetPair.first = 0;
5697  RetPair.second = 0;
5698  Utilities->CallLogPop(514);
5699  return(RetPair); // nothing found
5700  }
5701  else
5702  {
5703  RetPair.first = InactiveTrackRange.first->second;
5704  RetPair.second = (--InactiveTrackRange.second)->second;
5705  FoundFlag = true;
5706  Utilities->CallLogPop(515);
5707  return(RetPair);
5708  }
5709 }
5710 
5711 // ---------------------------------------------------------------------------
5712 
5713 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5714 {
5715 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5717  AnsiString(DivergingPosition));
5718  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5719  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5720  int SpeedTag1 = T1.SpeedTag;
5721  int SpeedTag2 = T2.SpeedTag;
5722 
5723  if(T1.Attribute != T2.Attribute)
5724  {
5725  Utilities->CallLogPop(516);
5726  return(false);
5727  }
5728  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5729  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5730  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5731  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5732  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5733  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5734  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5735  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5736  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5737  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5738  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5739  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5740  {
5741  Utilities->CallLogPop(517);
5742  return(true);
5743  }
5744  else
5745  {
5746  Utilities->CallLogPop(518);
5747  return(false);
5748  }
5749 }
5750 
5751 // ---------------------------------------------------------------------------
5752 
5753 /*
5754  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5755  {
5756  if(lower.second < higher.second) return true;
5757  else if(lower.second > higher.second) return false;
5758  else if(lower.second == higher.second)
5759  {
5760  if(lower.first < higher.first) return true;
5761  }
5762  return false;
5763  }
5764 */
5765 // ---------------------------------------------------------------------------
5766 
5767 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5768 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5769 {
5770  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5771  if(TrackElement.TrackType != GapJump)
5772  {
5773  throw Exception("Error, Wrong track type in PlotGap");
5774  }
5775  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5776  {
5777  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5778  }
5779  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5780  {
5781  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5782  }
5783  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5784  {
5785  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5786  }
5787  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5788  {
5789  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5790  }
5791  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5792  {
5793  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5794  }
5795  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5796  {
5797  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5798  }
5799  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5800  {
5801  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5802  }
5803  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5804  {
5805  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5806  }
5807  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5808  {
5809  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5810  }
5811  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5812  {
5813  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5814  }
5815  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5816  {
5817  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5818  }
5819  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5820  {
5821  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5822  }
5823  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5824  {
5825  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5826  }
5827  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5828  {
5829  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5830  }
5831  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5832  {
5833  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5834  }
5835  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5836  {
5837  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5838  }
5839  Utilities->CallLogPop(1101);
5840 }
5841 
5842 // ---------------------------------------------------------------------------
5843 
5844 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5845 {
5846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5847  if(TrackElement.TrackType != Points)
5848  {
5849  throw Exception("Error, Wrong track type in PlotPoints");
5850  }
5851  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5852  TrackElement.PlotVariableTrackElement(4, Disp);
5853  if(BothFillets)
5854  {
5855  if(TrackElement.SpeedTag < 28)
5856  {
5857  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5858  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5859  }
5860  else if(TrackElement.SpeedTag < 132)
5861  {
5862  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5863  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5864  }
5865  else
5866  {
5867  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5868  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5869  }
5870  }
5871  else
5872  {
5873  if(TrackElement.SpeedTag < 28)
5874  {
5875  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5876  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5877  }
5878  else if(TrackElement.SpeedTag < 132)
5879  {
5880  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5881  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5882  }
5883  else
5884  {
5885  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5886  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5887  }
5888  }
5889 // replot platform if required
5890  TIMPair IMPair;
5891  bool FoundFlag;
5892 
5893  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5894  if(FoundFlag)
5895  {
5896  // only one platform possible at points so only need to plot IMPair.first
5897  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5898  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5899  }
5900  Utilities->CallLogPop(519);
5901 }
5902 
5903 // ---------------------------------------------------------------------------
5904 
5905 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5906 {
5907 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5909  if(TrackElement.TrackType != SignalPost)
5910  {
5911  throw Exception("Error, Wrong track type in PlotSignal");
5912  }
5913  for(int x = 0; x < 40; x++)
5914  {
5915  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5916  {
5917  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5918  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5919 // in case existing signal is a double yellow
5920  // plot platforms if present
5921 // Graphics::TBitmap* SignalPlatformGraphic;
5922 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5923 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5924 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5925 // to not be plotted with the above function.
5926  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5927  // now plot signal (double yellow overwrites most of signal platform if present)
5928  // additions at version 0.6 for other aspects & ground sigs
5929  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5930  {
5931  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5932  }
5933  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5934  {
5935  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5936  }
5937  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5938  {
5939  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5940  }
5941  else // 4 aspect
5942  {
5943  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5944  }
5945  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5946  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5947  {
5948  if(TrackElement.SpeedTag == 68)
5949  {
5950  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5951  }
5952  if(TrackElement.SpeedTag == 69)
5953  {
5954  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5955  }
5956  if(TrackElement.SpeedTag == 70)
5957  {
5958  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5959  }
5960  if(TrackElement.SpeedTag == 71)
5961  {
5962  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5963  }
5964  if(TrackElement.SpeedTag == 72)
5965  {
5966  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5967  }
5968  if(TrackElement.SpeedTag == 73)
5969  {
5970  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5971  }
5972  if(TrackElement.SpeedTag == 74)
5973  {
5974  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5975  }
5976  if(TrackElement.SpeedTag == 75)
5977  {
5978  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5979  }
5980  }
5981  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5982  // ground signal calling on, need to use normal proceed aspect
5983  {
5984  for(int x = 0; x < 40; x++)
5985  {
5986  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5987  {
5988  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5989  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5990  // plot special signal platform if present
5991  Graphics::TBitmap* SignalPlatformGraphic;
5992  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5993  // now plot signal
5994  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5995  }
5996  }
5997  }
5998  break;
5999  }
6000  }
6001  Utilities->CallLogPop(520);
6002 }
6003 
6004 // ---------------------------------------------------------------------------
6005 
6006 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6007 {
6008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6009  bool FoundFlag;
6010  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6011 
6012  if(!FoundFlag)
6013  {
6014  Utilities->CallLogPop(2112);
6015  return;
6016  }
6017  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6018  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6019 
6020  // don't want 'else if' for the below as may need to plot 2 platforms
6021  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6022  {
6023  if(IAElement1.LocationName == "") // '2' will be same
6024  {
6025  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6026  }
6027  else
6028  {
6029  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6030  }
6031  }
6032  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6033  {
6034  if(IAElement1.LocationName == "") // '2' will be same
6035  {
6036  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6037  }
6038  else
6039  {
6040  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6041  }
6042  }
6043  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6044  {
6045  if(IAElement1.LocationName == "") // '2' will be same
6046  {
6047  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6048  }
6049  else
6050  {
6051  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6052  }
6053  }
6054  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6055  {
6056  if(IAElement1.LocationName == "") // '2' will be same
6057  {
6058  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6059  }
6060  else
6061  {
6062  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6063  }
6064  }
6065  Utilities->CallLogPop(2113);
6066 }
6067 
6068 // ---------------------------------------------------------------------------
6069 
6070 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6071 {
6072 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6073  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6074  AnsiString(VLoc));
6075 // find topmost LC, opening them all (to trains) in turn
6076  int UpStep = 0;
6077 
6078  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6079  {
6080  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6081  UpStep--;
6082  }
6083 // now find bottommost LC, opening them all (to trains) in turn
6084  int DownStep = 1;
6085 
6086  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6087  {
6088  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6089  DownStep++;
6090  }
6091 // find leftmost LC, opening them all (to trains) in turn
6092  int LeftStep = 0;
6093 
6094  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6095  {
6096  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6097  LeftStep--;
6098  }
6099 // now find rightmost LC, opening them all (to trains) in turn
6100  int RightStep = 1;
6101 
6102  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6103  {
6104  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6105  RightStep++;
6106  }
6107  Utilities->CallLogPop(1915);
6108 }
6109 
6110 // ---------------------------------------------------------------------------
6111 
6112 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6113 {
6114  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6115 // work upwards setting all to manual
6116  int UpStep = -1;
6117 
6118  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6119  {
6120  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6121  UpStep--;
6122  }
6123 // work downwards setting all to manual
6124  int DownStep = 1;
6125 
6126  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6127  {
6128  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6129  DownStep++;
6130  }
6131 // work leftwards setting all to manual
6132  int LeftStep = -1;
6133 
6134  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6135  {
6136  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6137  LeftStep--;
6138  }
6139 // work rightwards setting all to manual
6140  int RightStep = 1;
6141 
6142  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6143  {
6144  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6145  RightStep++;
6146  }
6147  Utilities->CallLogPop(2242);
6148 }
6149 
6150 // ---------------------------------------------------------------------------
6151 
6152 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6153 {
6154  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6156  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6157  {
6158  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6159  {
6160  BarriersDownVector.at(x).TypeOfRoute = 2;
6161  break;
6162  }
6163  }
6164  Utilities->CallLogPop(2243);
6165 }
6166 
6167 // ---------------------------------------------------------------------------
6168 
6169 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6170 {
6171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6172 // work upwards
6173  int UpStep = 0; //start with this location
6174 
6175  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6176  {
6177  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6178  {
6179  Utilities->CallLogPop(2244);
6180  return(true);
6181  }
6182  UpStep--;
6183  }
6184 // work downwards
6185  int DownStep = 1;
6186 
6187  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6188  {
6189  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6190  {
6191  Utilities->CallLogPop(2245);
6192  return(true);
6193  }
6194  DownStep++;
6195  }
6196 // work leftwards
6197  int LeftStep = -1;
6198 
6199  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6200  {
6201  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6202  {
6203  Utilities->CallLogPop(2246);
6204  return(true);
6205  }
6206  LeftStep--;
6207  }
6208 // work rightwards
6209  int RightStep = 1;
6210 
6211  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6212  {
6213  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6214  {
6215  Utilities->CallLogPop(2247);
6216  return(true);
6217  }
6218  RightStep++;
6219  }
6220  Utilities->CallLogPop(2248);
6221  return(false);
6222 }
6223 
6224 // ---------------------------------------------------------------------------
6225 
6226 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6227 {
6228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6229  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6230  {
6231  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6232  {
6233  BDVectorPos = x;
6234  Utilities->CallLogPop(2249);
6235  return(true);
6236  }
6237  }
6238  BDVectorPos = -1;
6239  Utilities->CallLogPop(2250);
6240  return(false);
6241 }
6242 
6243 // ---------------------------------------------------------------------------
6244 
6245 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6246 // open to trains
6247 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6248 {
6249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6250  AnsiString(VLoc));
6251  if(!IsLCAtHV(4, HLoc, VLoc))
6252  {
6253  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6254  }
6255  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6256  {
6257  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6258  }
6259 // check for adjacent LCs & if so open (to trains)
6260  if(BaseElementSpeedTag == 1) // hor track element
6261  {
6262  // find topmost LC, opening them all (to trains) in turn
6263  int UpStep = 0;
6264  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6265  {
6266  UpStep--;
6267  }
6268  UpStep++;
6269  // now find bottommost LC, opening them all (to trains) in turn
6270  int DownStep = 1;
6271  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6272  {
6273  DownStep++;
6274  }
6275  DownStep--;
6276  // now plot graphics, UpStep is smallest & DownStep largest
6277  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6278  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6279  Graphics::TBitmap *RouteGraphic;
6280  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6281  if(TypeOfRoute == 1)
6282  {
6283  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6284  }
6285  else if(TypeOfRoute == 0)
6286  {
6287  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6288  }
6289  else //manual - no route
6290  {
6291  RouteGraphic = BaseGraphic;
6292  }
6293 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6294 // LinkSigRouteGraphicsPtr[1] ver }
6295 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6296 // LinkNonSigRouteGraphicsPtr[1] ver }
6297 
6298  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6299  {
6300  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6301  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6302  if(!Manual)
6303  {
6304  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6305  }
6306  else
6307  {
6308  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6309  }
6310  }
6311  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6312  {
6313  if(UpStep == 0)
6314  {
6315  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6316  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6317  if(!Manual)
6318  {
6319  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6320  }
6321  else
6322  {
6323  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6324  }
6325  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6326  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6327  if(!Manual)
6328  {
6329  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6330  }
6331  else
6332  {
6333  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6334  }
6335  }
6336  else
6337  {
6338  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6339  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6340  if(!Manual)
6341  {
6342  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6343  }
6344  else
6345  {
6346  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6347  }
6348  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6349  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6350  if(!Manual)
6351  {
6352  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6353  }
6354  else
6355  {
6356  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6357  }
6358  }
6359  }
6360  else // at least one plain graphic
6361  {
6362  if(UpStep == 0)
6363  {
6364  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6365  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6366  if(!Manual)
6367  {
6368  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6369  }
6370  else
6371  {
6372  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6373  }
6374  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6375  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6376  if(!Manual)
6377  {
6378  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6379  }
6380  else
6381  {
6382  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6383  }
6384  }
6385  else if(DownStep == 0)
6386  {
6387  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6388  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6389  if(!Manual)
6390  {
6391  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6392  }
6393  else
6394  {
6395  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6396  }
6397  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6398  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6399  if(!Manual)
6400  {
6401  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6402  }
6403  else
6404  {
6405  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6406  }
6407  }
6408  else
6409  {
6410  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6411  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6412  if(!Manual)
6413  {
6414  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6415  }
6416  else
6417  {
6418  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6419  }
6420  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6421  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6422  if(!Manual)
6423  {
6424  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6425  }
6426  else
6427  {
6428  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6429  }
6430  }
6431  for(int x = (UpStep + 1); x < DownStep; x++)
6432  {
6433  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6434  if(x == 0)
6435  {
6436  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6437  }
6438  else
6439  {
6440  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6441  }
6442  if(!Manual)
6443  {
6444  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6445  }
6446  else
6447  {
6448  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6449  }
6450  }
6451  }
6452  Disp->Update();
6453  Utilities->CallLogPop(1958);
6454  return;
6455  }
6456 
6457  else // ver track element
6458  {
6459  // find leftmost LC, opening them all (to trains) in turn
6460  int LStep = 0;
6461  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6462  {
6463  LStep--;
6464  }
6465  LStep++;
6466  // now find rightmost LC, opening them all (to trains) in turn
6467  int RStep = 1;
6468  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6469  {
6470  RStep++;
6471  }
6472  RStep--;
6473  // now plot graphics, LStep is smallest & RStep largest
6474  Graphics::TBitmap *RouteGraphic;
6475  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6476  if(TypeOfRoute == 1)
6477  {
6478  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6479  }
6480  else if(TypeOfRoute == 0)
6481  {
6482  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6483  }
6484  else //manual
6485  {
6486  RouteGraphic = BaseGraphic;
6487  }
6488 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6489 // LinkSigRouteGraphicsPtr[1] ver }
6490 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6491 // LinkNonSigRouteGraphicsPtr[1] ver }
6492  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6493  {
6494  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6495  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6496  if(!Manual)
6497  {
6498  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6499  }
6500  else
6501  {
6502  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6503  }
6504  }
6505  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6506  {
6507  if(LStep == 0)
6508  {
6509  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6510  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6511  if(!Manual)
6512  {
6513  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6514  }
6515  else
6516  {
6517  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6518  }
6519  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6520  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6521  if(!Manual)
6522  {
6523  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6524  }
6525  else
6526  {
6527  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6528  }
6529  }
6530  else
6531  {
6532  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6533  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6534  if(!Manual)
6535  {
6536  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6537  }
6538  else
6539  {
6540  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6541  }
6542  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6543  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6544  if(!Manual)
6545  {
6546  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6547  }
6548  else
6549  {
6550  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6551  }
6552  }
6553  }
6554  else // at least one plain graphic
6555  {
6556  if(LStep == 0)
6557  {
6558  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6559  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6560  if(!Manual)
6561  {
6562  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6563  }
6564  else
6565  {
6566  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6567  }
6568  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6569  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6570  if(!Manual)
6571  {
6572  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6573  }
6574  else
6575  {
6576  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6577  }
6578  }
6579  else if(RStep == 0)
6580  {
6581  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6582  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6583  if(!Manual)
6584  {
6585  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6586  }
6587  else
6588  {
6589  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6590  }
6591  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6592  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6593  if(!Manual)
6594  {
6595  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6596  }
6597  else
6598  {
6599  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6600  }
6601  }
6602  else
6603  {
6604  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6605  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6606  if(!Manual)
6607  {
6608  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6609  }
6610  else
6611  {
6612  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6613  }
6614  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6615  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6616  if(!Manual)
6617  {
6618  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6619  }
6620  else
6621  {
6622  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6623  }
6624  }
6625  for(int x = (LStep + 1); x < RStep; x++)
6626  {
6627  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6628  if(x == 0)
6629  {
6630  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6631  }
6632  else
6633  {
6634  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6635  }
6636  if(!Manual)
6637  {
6638  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6639  }
6640  else
6641  {
6642  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6643  }
6644  }
6645  }
6646  Disp->Update();
6647  Utilities->CallLogPop(1896);
6648  return;
6649  }
6650 }
6651 
6652 // ---------------------------------------------------------------------------
6653 
6654 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6655 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6656 {
6657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6658  AnsiString(HLoc) + "," + AnsiString(VLoc));
6659  if(!IsLCAtHV(29, HLoc, VLoc))
6660  {
6661  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6662  }
6663  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6664  {
6665  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6666  }
6667 // check for adjacent LCs & if so open (to trains)
6668  if(BaseElementSpeedTag == 1) // hor track element
6669  {
6670  // find topmost LC, opening them all (to trains) in turn
6671  int UpStep = 0;
6672  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6673  {
6674  UpStep--;
6675  }
6676  UpStep++;
6677  // now find bottommost LC, opening them all (to trains) in turn
6678  int DownStep = 1;
6679  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6680  {
6681  DownStep++;
6682  }
6683  DownStep--;
6684  // now plot graphics, UpStep is smallest & DownStep largest
6685  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6686  {
6687  if(!Manual)
6688  {
6689  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6690  }
6691  else
6692  {
6693  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6694  }
6695  }
6696  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6697  {
6698  if(!Manual)
6699  {
6700  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6701  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6702  }
6703  else
6704  {
6705  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6706  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6707  }
6708  }
6709  else // at least one plain graphic
6710  {
6711  if(!Manual)
6712  {
6713  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6714  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6715  for(int x = (UpStep + 1); x < DownStep; x++)
6716  {
6717  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6718  }
6719  }
6720  else
6721  {
6722  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6723  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6724  for(int x = (UpStep + 1); x < DownStep; x++)
6725  {
6726  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6727  }
6728  }
6729  }
6730  // set markers
6731  for(int x = UpStep; x <= DownStep; x++)
6732  {
6733  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6734  }
6735  Display->Update();
6736  Utilities->CallLogPop(1944);
6737  return;
6738  }
6739 
6740  else // ver track element
6741  {
6742  // find leftmost LC, opening them all (to trains) in turn
6743  int LStep = 0;
6744  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6745  {
6746  LStep--;
6747  }
6748  LStep++;
6749  // now find rightmost LC, opening them all (to trains) in turn
6750  int RStep = 1;
6751  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6752  {
6753  RStep++;
6754  }
6755  RStep--;
6756  // now plot graphics, LStep is smallest & RStep largest
6757  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6758  {
6759  if(!Manual)
6760  {
6761  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6762  }
6763  else
6764  {
6765  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6766  }
6767  }
6768  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6769  {
6770  if(!Manual)
6771  {
6772  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6773  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6774  }
6775  else
6776  {
6777  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6778  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6779  }
6780  }
6781  else // at least one plain graphic
6782  {
6783  if(!Manual)
6784  {
6785  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6786  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6787  for(int x = (LStep + 1); x < RStep; x++)
6788  {
6789  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6790  }
6791  }
6792  else
6793  {
6794  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6795  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6796  for(int x = (LStep + 1); x < RStep; x++)
6797  {
6798  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6799  }
6800  }
6801  }
6802  // set markers
6803  for(int x = LStep; x <= RStep; x++)
6804  {
6805  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6806  }
6807  Disp->Update();
6808  Utilities->CallLogPop(1945);
6809  return;
6810  }
6811 }
6812 
6813 // ---------------------------------------------------------------------------
6814 
6815 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6816 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6817 {
6818  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6819  AnsiString(VLoc));
6820  if(!IsLCAtHV(9, HLoc, VLoc))
6821  {
6822  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6823  }
6824  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6825  {
6826  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6827  }
6828 // check for adjacent LCs & if so close (to trains)
6829  if(BaseElementSpeedTag == 1) // hor track element
6830  {
6831  // find topmost LC, closing them all (to trains) in turn
6832  int UpStep = 0;
6833  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6834  {
6835  UpStep--;
6836  }
6837  UpStep++;
6838  // now find bottommost LC, opening them all (to trains) in turn
6839  int DownStep = 1;
6840  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6841  {
6842  DownStep++;
6843  }
6844  DownStep--;
6845  // now plot graphics, UpStep is smallest & DownStep largest
6846  for(int x = UpStep; x < (DownStep + 1); x++)
6847  {
6848  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6849  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6850  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6851  }
6852  Disp->Update();
6853  Utilities->CallLogPop(1959);
6854  return;
6855  }
6856 
6857  else // ver track element
6858  {
6859  // find leftmost LC, closing them all (to trains) in turn
6860  int LStep = 0;
6861  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6862  {
6863  LStep--;
6864  }
6865  LStep++;
6866  // now find rightmost LC, opening them all (to trains) in turn
6867  int RStep = 1;
6868  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6869  {
6870  RStep++;
6871  }
6872  RStep--;
6873  // now plot graphics, LStep is smallest & RStep largest
6874  for(int x = LStep; x < (RStep + 1); x++)
6875  {
6876  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6877  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6878  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6879  }
6880  Disp->Update();
6881  Utilities->CallLogPop(1960);
6882  return;
6883  }
6884 }
6885 
6886 // ---------------------------------------------------------------------------
6887 
6888 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6889 // closed to trains
6890 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6891 {
6892  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6893  AnsiString(HLoc) + "," + AnsiString(VLoc));
6894  if(!IsLCAtHV(34, HLoc, VLoc))
6895  {
6896  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6897  }
6898  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6899  {
6900  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6901  }
6902  TTrackElement TE;
6903 
6904 // check for adjacent LCs & if so close (to trains)
6905  if(BaseElementSpeedTag == 1) // hor track element
6906  {
6907  // find topmost LC, closing them all (to trains) in turn
6908  int UpStep = 0;
6909  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6910  {
6911  UpStep--;
6912  }
6913  UpStep++;
6914  // now find bottommost LC, opening them all (to trains) in turn
6915  int DownStep = 1;
6916  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6917  {
6918  DownStep++;
6919  }
6920  DownStep--;
6921  // now plot graphics, UpStep is smallest & DownStep largest
6922  for(int x = UpStep; x <= DownStep; x++)
6923  {
6924  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6925  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6926  }
6927  Display->Update();
6928  Utilities->CallLogPop(1946);
6929  return;
6930  }
6931 
6932  else // ver track element
6933  {
6934  // find leftmost LC, closing them all (to trains) in turn
6935  int LStep = 0;
6936  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6937  {
6938  LStep--;
6939  }
6940  LStep++;
6941  // now find rightmost LC, opening them all (to trains) in turn
6942  int RStep = 1;
6943  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6944  {
6945  RStep++;
6946  }
6947  RStep--;
6948  // now plot graphics, LStep is smallest & RStep largest
6949  for(int x = LStep; x <= RStep; x++)
6950  {
6951  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6952  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6953  }
6954  Display->Update();
6955  Utilities->CallLogPop(1947);
6956  return;
6957  }
6958 }
6959 
6960 // ---------------------------------------------------------------------------
6961 
6962 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
6963 {
6964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6965  Graphics::TBitmap *RouteGraphic;
6966  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6967 
6968  if(BaseElementSpeedTag == 1)
6969  {
6970  if(TypeOfRoute == 1)
6971  {
6972  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6973  }
6974  else if(TypeOfRoute == 0)
6975  {
6976  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6977  }
6978  else //manual
6979  {
6980  RouteGraphic = BaseGraphic;
6981  }
6982  if(State == Raising)
6983  {
6984  RouteGraphic = BaseGraphic;
6985  }
6986  }
6987  else
6988  {
6989  BaseGraphic = RailGraphics->gl2;
6990  if(TypeOfRoute == 1)
6991  {
6992  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6993  }
6994  else if(TypeOfRoute == 0)
6995  {
6996  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6997  }
6998  else
6999  {
7000  RouteGraphic = BaseGraphic; //manual
7001  }
7002  if(State == Raising)
7003  {
7004  RouteGraphic = BaseGraphic;
7005  }
7006  }
7007  int UpStep = 0;
7008 
7009  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7010  {
7011  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7012  if(UpStep == 0)
7013  {
7014  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7015  }
7016  else
7017  {
7018  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7019  }
7020  UpStep--;
7021  }
7022 // now find bottommost LC, opening them all (to trains) in turn
7023  int DownStep = 1;
7024 
7025  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7026  {
7027  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7028  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7029  DownStep++;
7030  }
7031  int LeftStep = 0;
7032 
7033  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7034  {
7035  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7036  if(LeftStep == 0)
7037  {
7038  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7039  }
7040  else
7041  {
7042  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7043  }
7044  LeftStep--;
7045  }
7046 // now find rightmost LC, opening them all (to trains) in turn
7047  int RightStep = 1;
7048 
7049  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7050  {
7051  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7052  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7053  RightStep++;
7054  }
7055  Disp->Update();
7056  Utilities->CallLogPop(1914);
7057 }
7058 
7059 // ---------------------------------------------------------------------------
7060 
7061 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7062 {
7063 // return false for no LC there, flashing or a closed (to trains) LC
7064  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7065  bool FoundFlag;
7066  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7067 
7068  if(!FoundFlag)
7069  {
7070  Utilities->CallLogPop(1898);
7071  return(false);
7072  }
7073  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7074  {
7075  Utilities->CallLogPop(1899);
7076  return(false);
7077  }
7078  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7079  {
7080  Utilities->CallLogPop(1900);
7081  return(true);
7082  }
7083  Utilities->CallLogPop(1901);
7084  return(false);
7085 }
7086 
7087 // ---------------------------------------------------------------------------
7088 
7089 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7090 {
7091 // return false for no LC there, flashing LC or open (to trains) LC
7092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7093  bool FoundFlag;
7094  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7095 
7096  if(!FoundFlag)
7097  {
7098  Utilities->CallLogPop(1922);
7099  return(false);
7100  }
7101  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7102  {
7103  Utilities->CallLogPop(1923);
7104  return(false);
7105  }
7106  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7107  {
7108  Utilities->CallLogPop(1924);
7109  return(true);
7110  }
7111  Utilities->CallLogPop(1925);
7112  return(false);
7113 }
7114 
7115 // ---------------------------------------------------------------------------
7116 
7117 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7118 {
7119 // return true for barrier in process of moving
7120  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7121  bool FoundFlag;
7122  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7123 
7124  if(!FoundFlag)
7125  {
7126  Utilities->CallLogPop(1918);
7127  return(false);
7128  }
7129  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7130  {
7131  Utilities->CallLogPop(1919);
7132  return(false);
7133  }
7134  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7135  {
7136  Utilities->CallLogPop(1920);
7137  return(true);
7138  }
7139  Utilities->CallLogPop(1921);
7140  return(false);
7141 }
7142 
7143 // ---------------------------------------------------------------------------
7144 
7145 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7146 {
7147 // return true for an LC at H&V
7148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7149  bool FoundFlag;
7150  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7151 
7152  if(!FoundFlag)
7153  {
7154  Utilities->CallLogPop(1902);
7155  return(false);
7156  }
7157  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7158  {
7159  Utilities->CallLogPop(1903);
7160  return(false);
7161  }
7162  Utilities->CallLogPop(1904);
7163  return(true);
7164 }
7165 
7166 // ---------------------------------------------------------------------------
7167 
7168 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7169 {
7170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7171  AnsiString(Attr));
7172  bool FoundFlag;
7173  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7174 
7175  if(!FoundFlag)
7176  {
7177  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7178  }
7179  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7180  {
7181  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7182  }
7183  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7184  Utilities->CallLogPop(1905);
7185  return;
7186 }
7187 
7188 // ---------------------------------------------------------------------------
7189 
7191 {
7192  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7193  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7194  {
7195  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7196  if(InactiveTrackElement.TrackType == LevelCrossing)
7197  {
7198  InactiveTrackElementAt(141, x).Attribute = 0;
7199  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7200  }
7201  }
7202  Utilities->CallLogPop(1913);
7203  return;
7204 }
7205 
7206 // ---------------------------------------------------------------------------
7207 
7208 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7209 {
7210 // return true if there is either a route set or being set on any element or a train on any element
7211  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7212  "," + AnsiString(VLoc));
7213 
7214  THVPair TrackMapKeyPair;
7215  TTrack::TTrackMapIterator TrackMapPtr;
7216  int DummyRouteNumber;
7217 
7218  TrainPresent = false;
7219 // find topmost LC, checking each for routes & trains
7220  int UpStep = 0;
7221 
7222  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7223  {
7224  TrackMapKeyPair.first = HLoc;
7225  TrackMapKeyPair.second = VLoc + UpStep;
7226  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7227  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7228  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7229  {
7230  Utilities->CallLogPop(1932);
7231  return(true);
7232  }
7233  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7234  {
7235  TrainPresent = true;
7236  Utilities->CallLogPop(1933);
7237  return(true);
7238  }
7239  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7240  {
7241  Utilities->CallLogPop(2274);
7242  return(true);
7243  }
7244  UpStep--;
7245  }
7246 // now find bottommost LC, opening them all (to trains) in turn
7247  int DownStep = 1;
7248 
7249  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7250  {
7251  TrackMapKeyPair.first = HLoc;
7252  TrackMapKeyPair.second = VLoc + DownStep;
7253  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7254  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7255  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7256  {
7257  Utilities->CallLogPop(1934);
7258  return(true);
7259  }
7260  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7261  {
7262  TrainPresent = true;
7263  Utilities->CallLogPop(1935);
7264  return(true);
7265  }
7266  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7267  {
7268  Utilities->CallLogPop(2275);
7269  return(true);
7270  }
7271  DownStep++;
7272  }
7273 // find leftmost LC
7274  int LeftStep = 0;
7275 
7276  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7277  {
7278  TrackMapKeyPair.first = HLoc + LeftStep;
7279  TrackMapKeyPair.second = VLoc;
7280  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7281  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7282  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7283  {
7284  Utilities->CallLogPop(1936);
7285  return(true);
7286  }
7287  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7288  {
7289  TrainPresent = true;
7290  Utilities->CallLogPop(1937);
7291  return(true);
7292  }
7293  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7294  {
7295  Utilities->CallLogPop(2276);
7296  return(true);
7297  }
7298  LeftStep--;
7299  }
7300 // now find rightmost LC, opening them all (to trains) in turn
7301  int RightStep = 1;
7302 
7303  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7304  {
7305  TrackMapKeyPair.first = HLoc + RightStep;
7306  TrackMapKeyPair.second = VLoc;
7307  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7308  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7309  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7310  {
7311  Utilities->CallLogPop(1938);
7312  return(true);
7313  }
7314  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7315  {
7316  TrainPresent = true;
7317  Utilities->CallLogPop(1939);
7318  return(true);
7319  }
7320  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7321  {
7322  Utilities->CallLogPop(2277);
7323  return(true);
7324  }
7325  RightStep++;
7326  }
7327  Utilities->CallLogPop(1940);
7328  return(false);
7329 }
7330 
7331 // ---------------------------------------------------------------------------
7332 
7333 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7334 {
7335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7336  for(unsigned int x = 0; x < SearchVector.size(); x++)
7337  {
7338  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7339  {
7340  Utilities->CallLogPop(2278);
7341  return(true);
7342  }
7343  }
7344  Utilities->CallLogPop(2279);
7345  return(false);
7346 }
7347 
7348 // ---------------------------------------------------------------------------
7349 
7350 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7351 {
7352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7353  AnsiString(HLoc) + "," + AnsiString(VLoc));
7354  if(!IsLCAtHV(60, HLoc, VLoc))
7355  {
7356  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7357  }
7358 
7359 // check for adjacent LCs
7360  // find topmost LC
7361  int UpStep = 0;
7362  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7363  {
7364  UpStep--;
7365  }
7366  UpStep++;
7367  // now find bottommost LC, opening them all (to trains) in turn
7368  int DownStep = 1;
7369  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7370  {
7371  DownStep++;
7372  }
7373  DownStep--;
7374  // now plot graphics, UpStep is smallest & DownStep largest
7375  for(int x = UpStep; x <= DownStep; x++)
7376  {
7377  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7378  }
7379 
7380  // find leftmost LC, closing them all (to trains) in turn
7381  int LStep = 0;
7382  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7383  {
7384  LStep--;
7385  }
7386  LStep++;
7387  // now find rightmost LC, opening them all (to trains) in turn
7388  int RStep = 1;
7389  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7390  {
7391  RStep++;
7392  }
7393  RStep--;
7394  // now plot graphics, LStep is smallest & RStep largest
7395  for(int x = LStep; x <= RStep; x++)
7396  {
7397  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7398  }
7399  Display->Update();
7400  Utilities->CallLogPop(2315);
7401  return;
7402 }
7403 
7404 // ---------------------------------------------------------------------------
7405 
7406 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7407 {
7408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7409  if(TrackElement.TrackType != Points)
7410  {
7411  throw Exception("Error, Wrong track type in GetFilletGraphic");
7412  }
7413  if(TrackElement.SpeedTag < 28)
7414  {
7415  Utilities->CallLogPop(521);
7416  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7417  }
7418  else if(TrackElement.SpeedTag < 132)
7419  {
7420  Utilities->CallLogPop(522);
7421 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7422  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7423  }
7424  else
7425  {
7426  Utilities->CallLogPop(1537);
7427  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7428  }
7429 }
7430 
7431 // ---------------------------------------------------------------------------
7432 
7434 {
7435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7436  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7437  {
7438  TrackElementAt(1351, x).TrainIDOnElement = -1;
7441  }
7442  Utilities->CallLogPop(1342);
7443 }
7444 
7445 // ---------------------------------------------------------------------------
7446 
7447 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7448 /*
7449  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7450 */
7451 {
7452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7453  AnsiString(ScreenPosV));
7454  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7455  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7456 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7457  Utilities->CallLogPop(535);
7458 }
7459 
7460 // ---------------------------------------------------------------------------
7461 
7462 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7463 /*
7464  Converts the screen position to the true (without offsets) position
7465 */
7466 {
7467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7468  AnsiString(ScreenPosV));
7469  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7470  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7471  Utilities->CallLogPop(536);
7472 }
7473 
7474 // ---------------------------------------------------------------------------
7475 
7476 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7477 {
7478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7479  AnsiString(VPosTrue));
7480  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7481  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7482  Utilities->CallLogPop(537);
7483 }
7484 
7485 // ---------------------------------------------------------------------------
7486 
7487 void TTrack::CheckMapAndTrack(int Caller) // test
7488 {
7489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7490  int Zeroes = 0;
7491  bool FoundFlag;
7492 
7493  for(unsigned int a = 0; a < TrackVector.size(); a++)
7494  {
7495  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7496  if(CheckElement.SpeedTag == 0)
7497  {
7498  Zeroes++; // zeroed elements not saved in map
7499  }
7500  else
7501  {
7502  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7503  if(!FoundFlag)
7504  {
7505  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7506  " in TrackMap, Caller=" + (AnsiString)Caller);
7507  }
7508  if(MapVecPos != (int)a)
7509  {
7510  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7511  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7512  (AnsiString)Caller);
7513  }
7514  }
7515  }
7516  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7517  {
7518  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7519  " Caller=" + (AnsiString)Caller);
7520  }
7521  Utilities->CallLogPop(538);
7522  return;
7523 }
7524 
7525 // ---------------------------------------------------------------------------
7526 
7527 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7528 {
7529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7530  bool FoundFlag;
7531  TIMPair InactivePair;
7532 
7533  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7534  {
7535  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7536  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7537  if(!FoundFlag)
7538  {
7539  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7540  " in InactiveMap, Caller=" + (AnsiString)Caller);
7541  }
7542  if((InactivePair.first != a) && (InactivePair.second != a))
7543  {
7544  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7545  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7546  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7547  }
7548  }
7549  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7550  {
7551  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7552  " Caller=" + (AnsiString)Caller);
7553  }
7554  Utilities->CallLogPop(539);
7555 }
7556 
7557 // ---------------------------------------------------------------------------
7558 
7559 void TTrack::CheckGapMap(int Caller) // test
7560 {
7561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7562  int Position1, Position2;
7563  TTrackElement TrackElement1, TrackElement2;
7564  TGapMapIterator GapMapPtr;
7565 
7566  if(!GapMap.empty())
7567  {
7568  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7569  {
7570  int HLoc1 = GapMapPtr->first.first;
7571  int VLoc1 = GapMapPtr->first.second;
7572  int HLoc2 = GapMapPtr->second.first;
7573  int VLoc2 = GapMapPtr->second.second;
7574  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7575  {
7576  throw Exception("Failed to find H & V for gap1, GapMap in error");
7577  }
7578  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7579  {
7580  throw Exception("Failed to find H & V for gap2, GapMap in error");
7581  }
7582  if(TrackElementAt(17, Position1).TrackType != GapJump)
7583  {
7584  throw Exception("Element at Pos1 not a gap, GapMap in error");
7585  }
7586  if(TrackElementAt(18, Position2).TrackType != GapJump)
7587  {
7588  throw Exception("Element at Pos2 not a gap, GapMap in error");
7589  }
7590  }
7591  }
7592  unsigned int GapCount = 0;
7593 
7594  for(unsigned int a = 0; a < TrackVector.size(); a++)
7595  {
7596  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7597  if(CheckElement.TrackType == GapJump)
7598  {
7599  GapCount++;
7600  }
7601  }
7602  if((GapMap.size() * 2) != GapCount)
7603  {
7604  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7605  (AnsiString)Caller);
7606  }
7607  Utilities->CallLogPop(540);
7608 }
7609 
7610 // ---------------------------------------------------------------------------
7611 
7612 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7613 {
7614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7615  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7616  {
7617  if(TrackFinished)
7618  {
7619  throw Exception("Error - TrackFinished with erase element still present");
7620  }
7621  Utilities->CallLogPop(541);
7622  return; // erased element, can't set ID
7623  }
7624  AnsiString IDString;
7625 
7626  if(TrackElement.HLoc < 0)
7627  {
7628  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7629  }
7630  else
7631  {
7632  IDString = AnsiString(TrackElement.HLoc) + "-";
7633  }
7634  if(TrackElement.VLoc < 0)
7635  {
7636  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7637  }
7638  else
7639  {
7640  IDString += AnsiString(TrackElement.VLoc);
7641  }
7642  TrackElement.ElementID = IDString;
7643  Utilities->CallLogPop(542);
7644 }
7645 
7646 // ---------------------------------------------------------------------------
7647 
7648 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7649 {
7650 // e.g. "8-13", "00008-13", "N43-N127", etc
7651  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7652  int DelimPos;
7653 
7654  for(int x = 1; x < String.Length() + 1; x++)
7655  {
7656  if(String.IsDelimiter("-", x))
7657  {
7658  DelimPos = x;
7659  break;
7660  }
7661  if(x == String.Length())
7662  {
7663  if(GiveMessages)
7664  {
7665  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7666  }
7667  Utilities->CallLogPop(543);
7668  return(-1);
7669  }
7670  }
7671  if(DelimPos == 1)
7672  {
7673  if(GiveMessages)
7674  {
7675  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7676  }
7677  Utilities->CallLogPop(544);
7678  return(-1);
7679  }
7680  if(DelimPos == String.Length())
7681  {
7682  if(GiveMessages)
7683  {
7684  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7685  }
7686  Utilities->CallLogPop(545);
7687  return(-1);
7688  }
7689  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7690  {
7691  if(GiveMessages)
7692  {
7693  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7694  }
7695  Utilities->CallLogPop(1508);
7696  return(-1);
7697  }
7698  int HLoc, VLoc;
7699 
7700  if(String.SubString(1, 1) != "N")
7701  {
7702  for(int x = 1; x < DelimPos; x++)
7703  {
7704  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7705  {
7706  if(GiveMessages)
7707  {
7708  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7709  }
7710  Utilities->CallLogPop(546);
7711  return(-1);
7712  }
7713  }
7714  }
7715  if(String.SubString(1, 1) == "N")
7716  {
7717  for(int x = 2; x < DelimPos; x++)
7718  {
7719  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7720  {
7721  if(GiveMessages)
7722  {
7723  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7724  }
7725  Utilities->CallLogPop(763);
7726  return(-1);
7727  }
7728  }
7729  }
7730  if(String.SubString(1, 1) == "N")
7731  {
7732  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7733  }
7734  else
7735  {
7736  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7737  }
7738  if(String.SubString(DelimPos + 1, 1) != "N")
7739  {
7740  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7741  {
7742  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7743  {
7744  if(GiveMessages)
7745  {
7746  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7747  }
7748  Utilities->CallLogPop(547);
7749  return(-1);
7750  }
7751  }
7752  }
7753  if(String.SubString(DelimPos + 1, 1) == "N")
7754  {
7755  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7756  {
7757  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7758  {
7759  if(GiveMessages)
7760  {
7761  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7762  }
7763  Utilities->CallLogPop(764);
7764  return(-1);
7765  }
7766  }
7767  }
7768  if(String.SubString(DelimPos + 1, 1) == "N")
7769  {
7770  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7771  }
7772  else
7773  {
7774  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7775  }
7776  THVPair HVPair(HLoc, VLoc);
7777  TTrackMapIterator TrackMapPtr;
7778 
7779  TrackMapPtr = TrackMap.find(HVPair);
7780  if(TrackMapPtr == TrackMap.end())
7781  {
7782  if(GiveMessages)
7783  {
7784  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7785  }
7786  Utilities->CallLogPop(548);
7787  return(-1);
7788  }
7789  Utilities->CallLogPop(549);
7790  return(TrackMapPtr->second);
7791 }
7792 
7793 // ---------------------------------------------------------------------------
7794 
7795 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7796 /*
7797  True for linked properly at both ends
7798 */
7799 {
7800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7801  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7802  int HLoc = TrackElement.HLoc;
7803  int VLoc = TrackElement.VLoc;
7804 
7805  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7806  {
7807  Utilities->CallLogPop(1821);
7808  return(false);
7809  }
7810  if(TrackElement.SpeedTag == 129) // vertical footbridge
7811  {
7812  // check top connection
7813  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7814  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7815  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7816  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7817  {
7818  Utilities->CallLogPop(550);
7819  return(false);
7820  }
7821  // check bottom connection
7822  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7823  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7824  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7825  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7826  {
7827  Utilities->CallLogPop(551);
7828  return(false);
7829  }
7830  }
7831  if(TrackElement.SpeedTag == 145) // vertical underpass
7832  {
7833  // check top connection
7834  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7835  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7836  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7837  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7838  {
7839  Utilities->CallLogPop(2114);
7840  return(false);
7841  }
7842  // check bottom connection
7843  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7844  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7845  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7846  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7847  {
7848  Utilities->CallLogPop(2115);
7849  return(false);
7850  }
7851  }
7852  if(TrackElement.SpeedTag == 130) // hor footbridge
7853  {
7854  // check left connection
7855  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7856  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7857  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7858  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7859  {
7860  Utilities->CallLogPop(552);
7861  return(false);
7862  }
7863  // check right connection
7864  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7865  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7866  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7867  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7868  {
7869  Utilities->CallLogPop(553);
7870  return(false);
7871  }
7872  }
7873  if(TrackElement.SpeedTag == 146) // hor u'pass
7874  {
7875  // check left connection
7876  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7877  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7878  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7879  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7880  {
7881  Utilities->CallLogPop(2116);
7882  return(false);
7883  }
7884  // check right connection
7885  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7886  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7887  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7888  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7889  {
7890  Utilities->CallLogPop(2117);
7891  return(false);
7892  }
7893  }
7894  Utilities->CallLogPop(554);
7895  return(true);
7896 }
7897 
7898 // ---------------------------------------------------------------------------
7899 
7900 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7901 /*
7902  return true if the SpeedTag present in the map at H & V
7903 */
7904 {
7905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7906  AnsiString(SpeedTag));
7907  if(InactiveTrack2MultiMap.empty())
7908  {
7909  Utilities->CallLogPop(555);
7910  return(false);
7911  }
7912  THVPair HVPair(HLoc, VLoc);
7914  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7915  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7916 
7917  if(HVRange.first == HVRange.second)
7918  {
7919  Utilities->CallLogPop(556);
7920  return(false);
7921  }
7922  else
7923  {
7924  HVIt1 = HVRange.first;
7925  }
7926  TTrackElement Temp1, Temp2; // test
7927 
7928  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7929  if(--HVRange.second != HVRange.first)
7930  {
7931  HVIt2 = HVRange.second;
7932  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7933  }
7934  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7935  HVIt2->second).SpeedTag == SpeedTag)))
7936  {
7937  Utilities->CallLogPop(557);
7938  return(true);
7939  }
7940  else
7941  {
7942  Utilities->CallLogPop(558);
7943  return(false);
7944  }
7945 }
7946 
7947 // ---------------------------------------------------------------------------
7948 
7949 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7950 /*
7951  return true if the SpeedTag present in the map at H & V
7952 */
7953 {
7954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7955  AnsiString(SpeedTag));
7956  if(TrackMap.empty())
7957  {
7958  Utilities->CallLogPop(559);
7959  return(false);
7960  }
7961  THVPair HVPair(HLoc, VLoc);
7962  TTrackMapIterator End = TrackMap.end();
7963  TTrackMapIterator It = End;
7964 
7965  It = TrackMap.find(HVPair);
7966  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7967  {
7968  Utilities->CallLogPop(560);
7969  return(true);
7970  }
7971  else
7972  {
7973  Utilities->CallLogPop(561);
7974  return(false);
7975  }
7976 }
7977 
7978 // ---------------------------------------------------------------------------
7979 
7980 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7981 {
7982 /*
7983  General:
7984  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7985  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7986  a NamedNonStationLocation.
7987  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7988  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7989  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7990  platform at that location).
7991 
7992  Linked named location elements are those explained in TTrack::TTrack()
7993 
7994  Detail:
7995  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7996  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7997  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7998  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7999  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8000  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8001 
8002  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8003  this function a single element should be in the List (normally from the user's selection but can also be from
8004  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8005  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8006  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8007  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8008  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8009  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8010  moves them into the Map. At the end all linked elements are in the Map.
8011 
8012  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8013  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8014  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8015 */
8016 
8017 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8018 // Display->FileDiagnostics(TestString);//test
8019 
8020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8021  AnsiString TestString1, TestString2; // test
8022 
8023  Track->LNDone2MultiMap.clear();
8024  if(LNPendingList.size() != 1)
8025  {
8026  throw Exception("LNPendingList size not 1 on entry");
8027  }
8028  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8029  while(!LNPendingList.empty())
8030  {
8031  CurrentElementNumber = LNPendingList.front();
8032  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8033  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8034  int H = CurrentElement->HLoc;
8035  int V = CurrentElement->VLoc;
8036  int Tag = CurrentElement->SpeedTag;
8037  if(Tag == 76) // top plat
8038  {
8039  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8040  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8041  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8042  for(int x = 0; x < 25; x++)
8043  {
8044  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8045  {
8046  LNPendingList.insert(LNPendingList.end(), NewElement);
8047  }
8048  }
8049  }
8050  else if(Tag == 77) // bot plat
8051  {
8052  for(int x = 0; x < 25; x++)
8053  {
8054  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8055  {
8056  LNPendingList.insert(LNPendingList.end(), NewElement);
8057  }
8058  }
8059  }
8060  else if(Tag == 78) // l plat
8061  {
8062  for(int x = 0; x < 25; x++)
8063  {
8064  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8065  {
8066  LNPendingList.insert(LNPendingList.end(), NewElement);
8067  }
8068  }
8069  }
8070  else if(Tag == 79) // r plat
8071  {
8072  for(int x = 0; x < 25; x++)
8073  {
8074  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8075  {
8076  LNPendingList.insert(LNPendingList.end(), NewElement);
8077  }
8078  }
8079  }
8080  else if(Tag == 96) // conc
8081  {
8082  for(int x = 0; x < 28; x++)
8083  {
8084  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8085  {
8086  LNPendingList.insert(LNPendingList.end(), NewElement);
8087  }
8088  }
8089  }
8090  else if(Tag == 129) // vert footbridge
8091  {
8092  for(int x = 0; x < 8; x++)
8093  {
8094  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8095  {
8096  LNPendingList.insert(LNPendingList.end(), NewElement);
8097  }
8098  }
8099  }
8100  else if(Tag == 130) // hor footbridge
8101  {
8102  for(int x = 0; x < 8; x++)
8103  {
8104  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8105  {
8106  LNPendingList.insert(LNPendingList.end(), NewElement);
8107  }
8108  }
8109  }
8110  else if(Tag == 131) // named location
8111  {
8112  for(int x = 0; x < 4; x++)
8113  {
8114  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8115  {
8116  LNPendingList.insert(LNPendingList.end(), NewElement);
8117  }
8118  }
8119  }
8120  else if(Tag == 145) // v u'pass
8121  {
8122  for(int x = 0; x < 8; x++)
8123  {
8124  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8125  {
8126  LNPendingList.insert(LNPendingList.end(), NewElement);
8127  }
8128  }
8129  }
8130  else if(Tag == 146) // h u'pass
8131  {
8132  for(int x = 0; x < 8; x++)
8133  {
8134  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8135  {
8136  LNPendingList.insert(LNPendingList.end(), NewElement);
8137  }
8138  }
8139  }
8140  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8141 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8142  if(AddingElements)
8143  {
8144  int HPos, VPos; // not used but needed for FindText function
8145  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8146  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8147  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8148  {
8149  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8150  if((ExistingName != "") && (ExistingName != LocationName))
8151  {
8152  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8153  {
8154  } // name not in LocationNameMultiMap, so don't erase from TextVector
8155  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8156  {
8157  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8158  {
8159  ;
8160  } // condition not used
8161 
8162  }
8163  }
8164  }
8165  }
8166  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8167  // track at that loc
8168  THVPair HVPair(H, V);
8169  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8170  LNDone2MultiMapEntry.first = HVPair;
8171  LNDone2MultiMapEntry.second = LNPendingList.front();
8172  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8173  LNPendingList.erase(LNPendingList.begin());
8174  }
8175 
8176 // search all name multimap for same name where corresponding active elements don't appear in
8177 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8178 
8179  TLocationNameMultiMapIterator SNIterator;
8180  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8181  bool FoundFlag, ErasedFlag = false;
8182 
8183  if(SNRange.first != SNRange.second)
8184  {
8185  SNRange.first--; // now pointing to before the first
8186  SNRange.second--; // now pointing to the last
8187  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8188  {
8189  // Same elements are in Done map as in name map
8190  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8191  {
8192  ErasedFlag = true;
8193  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8194  TVIt->LocationName = "";
8195  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8196  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8197  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8198  {
8199  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8200  if(FoundFlag)
8201  {
8202  TrackElementAt(20, Position).LocationName = "";
8203  TrackElementAt(21, Position).ActiveTrackElementName = "";
8204  }
8205  }
8206  // erase name in name map
8207 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8208  }
8209  }
8210  }
8211  if(ErasedFlag)
8212  {
8214  }
8215  if(TrackFinished)
8216  {
8218  }
8219 // set here as well as in LinkTrack so don't have to link track just because a name added
8220 // if track not finished then will be set when track validated
8221 
8222 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8223 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8224 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8225 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8226 // so the error would be seen.
8227 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8228  std::pair<AnsiString, char>TempMapPair;
8229 
8230  ContinuationNameMap.clear();
8231  for(int x = 0; x < Track->TrackVectorSize(); x++)
8232  {
8233  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8234  {
8235  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8236  TempMapPair.second = 'x'; // unused
8237  ContinuationNameMap.insert(TempMapPair);
8238  }
8239  }
8240 //end of addition
8241  CheckLocationNameMultiMap(1); // test
8242  Utilities->CallLogPop(562);
8243 }
8244 
8245 // ---------------------------------------------------------------------------
8246 
8247 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8248 /*
8249  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8250  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8251 */
8252 {
8253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8254  AnsiString(SpeedTag));
8255  if(!NamedLocationElementAt(2, HLoc, VLoc))
8256  {
8257  Utilities->CallLogPop(948);
8258  return(false);
8259  }
8260  bool FoundFlag;
8261  int Position = -1;
8262  TIMPair IMPair;
8263 
8264  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8265  {
8266  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8267  if(FoundFlag)
8268  {
8269  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8270  {
8271  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8272  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8273  // don't allow duplicates in either list, or processing takes a lot longer
8274  {
8275  FoundElement = MapPos;
8276  Utilities->CallLogPop(563);
8277  return(true);
8278  }
8279  }
8280  }
8281  }
8282  else
8283  {
8284  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8285  if(FoundFlag)
8286  {
8287  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8288  {
8289  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8290  {
8291  FoundElement = IMPair.first;
8292  Utilities->CallLogPop(564);
8293  return(true);
8294  }
8295  }
8296  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8297  {
8298  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8299  {
8300  FoundElement = IMPair.second;
8301  Utilities->CallLogPop(565);
8302  return(true);
8303  }
8304  }
8305  }
8306  }
8307  Utilities->CallLogPop(566);
8308  return(false);
8309 }
8310 
8311 // ---------------------------------------------------------------------------
8312 
8313 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8314 /*
8315  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8316  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8317  with the new name
8318 */
8319 {
8320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8321  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8322 
8323  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8324  int HLoc = TrackElement->HLoc;
8325  int VLoc = TrackElement->VLoc;
8326  bool FoundFlag;
8327 
8328  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8329  // only have timetable names for adjacent platforms & named locations
8330  {
8331  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8332  if(FoundFlag)
8333  {
8334  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8335  }
8336  }
8337  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8338 
8339  if(ErrorString != "")
8340  {
8341  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8342  }
8343  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8344  CheckLocationNameMultiMap(2); // test
8345  Utilities->CallLogPop(567);
8346 }
8347 
8348 // ---------------------------------------------------------------------------
8349 
8350 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8351 /*
8352  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8353 */
8354 {
8355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8356  if(LNDone2MultiMap.empty())
8357  {
8358  Utilities->CallLogPop(568);
8359  return(false);
8360  }
8361  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8362 
8363  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8364  {
8365  if(LNDone2MultiMapIterator->second == MapPos)
8366  {
8367  Utilities->CallLogPop(569);
8368  return(true);
8369  }
8370  }
8371  Utilities->CallLogPop(570);
8372  return(false);
8373 }
8374 
8375 // ---------------------------------------------------------------------------
8376 
8377 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8378 /*
8379  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8380 */
8381 {
8382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8383  if(LNPendingList.empty())
8384  {
8385  Utilities->CallLogPop(571);
8386  return(false);
8387  }
8388  TLNPendingListIterator LNPendingListIterator;
8389 
8390  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8391  {
8392  if(*LNPendingListIterator == MapPos)
8393  {
8394  Utilities->CallLogPop(572);
8395  return(true);
8396  }
8397  }
8398  Utilities->CallLogPop(573);
8399  return(false);
8400 }
8401 
8402 // ---------------------------------------------------------------------------
8403 
8404 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8405 /*
8406  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8407 */
8408 {
8409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8410  THVPair HVPair(HLoc, VLoc);
8411  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8412  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8413 
8414  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8415  {
8416  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8417  {
8418  Utilities->CallLogPop(574);
8419  return(true);
8420  }
8421  }
8422  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8423  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8424  {
8425  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8426  {
8427  Utilities->CallLogPop(575);
8428  return(true);
8429  }
8430  }
8431  Utilities->CallLogPop(576);
8432  return(false);
8433 }
8434 
8435 // ---------------------------------------------------------------------------
8436 
8437 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8438 {
8439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8440  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8441  {
8442  Utilities->CallLogPop(1953);
8443  return(true);
8444  }
8445  Utilities->CallLogPop(1954);
8446  return(false);
8447 }
8448 
8449 // ---------------------------------------------------------------------------
8450 
8451 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8452 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8453 //program and used when try to save as a .rly file
8454 {
8455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8458  if(LocationNameMultiMap.empty()) //no names so no duplicates
8459  {
8460  Utilities->CallLogPop(2254);
8461  return(false);
8462  }
8463  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8464  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8465  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8466  {
8468  {
8469  if(GiveMessage)
8470  {
8471  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8472  }
8473  Utilities->CallLogPop(2255);
8474  return(true);
8475  }
8476  }
8477  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8478  {
8479  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8480  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8481  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8482  {
8484  {
8485  if(GiveMessage)
8486  {
8487  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8488  }
8489  Utilities->CallLogPop(2256);
8490  return(true);
8491  }
8492  }
8493  }
8494  Utilities->CallLogPop(2257);
8495  return(false); //OK, no duplicates
8496 }
8497 
8498 // ---------------------------------------------------------------------------
8499 
8501 {
8502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8503  THVPair HVPair;
8504  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8505  //for use in the duplicate check
8506  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8507  {
8508  if(LNMMIt->second < 0) //active track element
8509  {
8510  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8511  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8512  }
8513  else //inactive track element
8514  {
8515  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8516  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8517  }
8518  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8519  }
8520  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8521 
8522  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8523  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8524  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8525 
8526  std::list<THVPair> HVLinkedList;
8527 
8528  //set the first value to true and add it to the list
8529  HVPairsLinkedMap.begin()->second = true;
8530  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8531  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8532  //examination
8533  THVPair HVPairUnderExamination;
8534  THVPairsLinkedMap::iterator HVPLMIt;
8535  THVPair HVPairNew;
8536  while(!HVLinkedList.empty())
8537  {
8538  HVPairUnderExamination = HVLinkedList.front();
8539  HVLinkedList.pop_front();
8540  HVPairNew.first = HVPairUnderExamination.first;
8541  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8542  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8543  if(HVPLMIt != HVPairsLinkedMap.end())
8544  {
8545  if(!HVPLMIt->second)
8546  {
8547  HVLinkedList.push_back(HVPLMIt->first);
8548  }
8549  HVPLMIt->second = true;
8550  }
8551  HVPairNew.first = HVPairUnderExamination.first - 1;
8552  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8553  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8554  if(HVPLMIt != HVPairsLinkedMap.end())
8555  {
8556  if(!HVPLMIt->second)
8557  {
8558  HVLinkedList.push_back(HVPLMIt->first);
8559  }
8560  HVPLMIt->second = true;
8561  }
8562  HVPairNew.first = HVPairUnderExamination.first;
8563  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8564  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8565  if(HVPLMIt != HVPairsLinkedMap.end())
8566  {
8567  if(!HVPLMIt->second)
8568  {
8569  HVLinkedList.push_back(HVPLMIt->first);
8570  }
8571  HVPLMIt->second = true;
8572  }
8573  HVPairNew.first = HVPairUnderExamination.first + 1;
8574  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8575  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8576  if(HVPLMIt != HVPairsLinkedMap.end())
8577  {
8578  if(!HVPLMIt->second)
8579  {
8580  HVLinkedList.push_back(HVPLMIt->first);
8581  }
8582  HVPLMIt->second = true;
8583  }
8584  }
8585 
8586  //at the end if any have a false bool then the name is duplicated so return false
8587  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8588  {
8589  if(!HVPLMIt->second)
8590  {
8591  Utilities->CallLogPop(2258);
8592  return(false);
8593  }
8594  }
8595  Utilities->CallLogPop(2259);
8596  return(true);
8597 }
8598 
8599 // ---------------------------------------------------------------------------
8600 
8601 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8602 /*
8603  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8604 */
8605 
8606 {
8607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8608  if(LocationName == "")
8609  {
8610  Utilities->CallLogPop(577);
8611  return(false);
8612  }
8613 // new for v0.2b
8614 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8616  {
8617  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8618  ActiveTrackElementNameMap.clear();
8619  for(unsigned int x = 0; x < TrackVector.size(); x++)
8620  {
8621  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8622  == ContinuationNameMap.end())
8623  {
8624  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8625  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8626  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8627  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8628  }
8629  }
8631  }
8632  Utilities->CallLogPop(578);
8633  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8634 // end of new section
8635 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8636 }
8637 
8638 // ---------------------------------------------------------------------------
8639 
8640 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8641 /*
8642  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8643  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8644  new names in the vectors.
8645 */
8646 {
8647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8648  bool FoundFlag, ErasedFlag = false;
8649  TLocationNameMultiMapIterator SNIterator;
8650  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8651 
8652  if(SNRange.first != SNRange.second)
8653  {
8654  ErasedFlag = true;
8655  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8656  {
8657  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8658  TVIt->LocationName = "";
8659  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8660  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8661  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8662  {
8663  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8664  if(FoundFlag)
8665  {
8666  TrackElementAt(25, Position).LocationName = "";
8667  TrackElementAt(26, Position).ActiveTrackElementName = "";
8668  }
8669  }
8670  }
8671  }
8672  if(ErasedFlag)
8673  {
8675  }
8676  CheckLocationNameMultiMap(3); // test
8677  Utilities->CallLogPop(579);
8678 }
8679 
8680 // ---------------------------------------------------------------------------
8681 
8682 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8683 /*
8684  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8685  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8686  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8687  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8688  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8689  naming up to date with the deletion or insertion.
8690 */
8691 {
8692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8693  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8694  LNPendingList.clear();
8695  AnsiString LocationName;
8696  int MapPos;
8697  bool FoundFlag = 0;
8698 
8699 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8700  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8701  if(FoundFlag)
8702  {
8703  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8704  if(LocationName != "")
8705  {
8706  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8707  EnterLocationName(13, LocationName, true);
8708  Utilities->CallLogPop(2251);
8709  return;
8710  }
8711  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8712  if(LocationName != "")
8713  {
8714  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8715  EnterLocationName(14, LocationName, true);
8716  Utilities->CallLogPop(2252);
8717  return;
8718  }
8719  }
8720 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8721 
8722  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8723  if(FoundFlag)
8724  {
8725  LocationName = TrackElementAt(1004, Position).LocationName;
8726  if(LocationName != "")
8727  {
8728  int ModifiedPosition = -1 - Position;
8729  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8730  EnterLocationName(15, LocationName, true);
8731  Utilities->CallLogPop(2253);
8732  return;
8733  }
8734  }
8735  if(SpeedTag == 76) // top plat
8736  {
8737  for(int x = 0; x < 25; x++)
8738  {
8739  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8740  {
8741  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8742  EnterLocationName(3, LocationName, true);
8743  break;
8744  }
8745  }
8746  }
8747  else if(SpeedTag == 77) // bot plat
8748  {
8749  for(int x = 0; x < 25; x++)
8750  {
8751  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8752  {
8753  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8754  EnterLocationName(4, LocationName, true);
8755  break;
8756  }
8757  }
8758  }
8759  else if(SpeedTag == 78) // l plat
8760  {
8761  for(int x = 0; x < 25; x++)
8762  {
8763  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8764  {
8765  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8766  EnterLocationName(5, LocationName, true);
8767  break;
8768  }
8769  }
8770  }
8771  else if(SpeedTag == 79) // r plat
8772  {
8773  for(int x = 0; x < 25; x++)
8774  {
8775  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8776  {
8777  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8778  EnterLocationName(6, LocationName, true);
8779  break;
8780  }
8781  }
8782  }
8783  else if(SpeedTag == 96) // conc
8784  {
8785  for(int x = 0; x < 28; x++)
8786  {
8787  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8788  {
8789  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8790  EnterLocationName(7, LocationName, true);
8791  break;
8792  }
8793  }
8794  }
8795  else if(SpeedTag == 129) // vert footbridge
8796  {
8797  for(int x = 0; x < 8; x++)
8798  {
8799  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8800  {
8801  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8802  EnterLocationName(8, LocationName, true);
8803  break;
8804  }
8805  }
8806  }
8807  else if(SpeedTag == 130) // hor footbridge
8808  {
8809  for(int x = 0; x < 8; x++)
8810  {
8811  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8812  {
8813  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8814  EnterLocationName(9, LocationName, true);
8815  break;
8816  }
8817  }
8818  }
8819  else if(SpeedTag == 145) // vert u'pass
8820  {
8821  for(int x = 0; x < 8; x++)
8822  {
8823  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8824  {
8825  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8826  EnterLocationName(11, LocationName, true);
8827  break;
8828  }
8829  }
8830  }
8831  else if(SpeedTag == 146) // hor u'pass
8832  {
8833  for(int x = 0; x < 8; x++)
8834  {
8835  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8836  {
8837  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8838  EnterLocationName(12, LocationName, true);
8839  break;
8840  }
8841  }
8842  }
8843  else if(SpeedTag == 131) // named location
8844  {
8845  for(int x = 0; x < 4; x++)
8846  {
8847  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8848  {
8849  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8850  EnterLocationName(10, LocationName, true);
8851  break;
8852  }
8853  }
8854  }
8855 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8856  Utilities->CallLogPop(580);
8857 }
8858 
8859 // ---------------------------------------------------------------------------
8860 
8861 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8862 /*
8863  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8864  true if a LocationName is found, and also returns the name and the adjusted vector position.
8865 */
8866 {
8867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8868  AnsiString(SpeedTag));
8869  bool FoundFlag;
8870  TIMPair IMPair;
8871  TTrackVectorIterator TempElement;
8872  int Position;
8873 
8874  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8875  if(FoundFlag)
8876  {
8877  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8878  {
8879  TempElement = InactiveTrackVector.begin() + IMPair.first;
8880  if(TempElement->LocationName != "")
8881  {
8882  LocationName = TempElement->LocationName;
8883  FoundElement = IMPair.first;
8884  Utilities->CallLogPop(581);
8885  return(true);
8886  }
8887  }
8888  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8889  {
8890  TempElement = InactiveTrackVector.begin() + IMPair.second;
8891  if(TempElement->LocationName != "")
8892  {
8893  LocationName = TempElement->LocationName;
8894  FoundElement = IMPair.second;
8895  Utilities->CallLogPop(582);
8896  return(true);
8897  }
8898  }
8899  }
8900  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8901  if(FoundFlag)
8902  {
8903  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8904  {
8905  TempElement = TrackVector.begin() + Position;
8906  if(TempElement->LocationName != "")
8907  {
8908  LocationName = TempElement->LocationName;
8909  FoundElement = -1 - Position;
8910  Utilities->CallLogPop(583);
8911  return(true);
8912  }
8913  }
8914  }
8915  Utilities->CallLogPop(584);
8916  return(false);
8917 }
8918 
8919 // ---------------------------------------------------------------------------
8920 
8921 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8922 {
8923 // check quantity in map & vectors match
8924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8925  unsigned int Count = 0;
8926 
8927  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8928  {
8929  Utilities->CallLogPop(2059);
8930  return;
8931  }
8932  AnsiString SName, TName, ErrorString;
8933 
8934  for(unsigned int x = 0; x < TrackVector.size(); x++)
8935  {
8936  if(TrackElementAt(1362, x).FixedNamedLocationElement)
8937  {
8938  if(TrackElementAt(1363, x).TrackType != FootCrossing)
8939  {
8940  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8941  AnsiString(Caller));
8942  }
8943  Count++;
8944  }
8945  }
8946  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8947  {
8948  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
8949  {
8950  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
8951  (InactiveTrackElementAt(146, x).TrackType != Concourse))
8952  {
8953  throw Exception
8954  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8955  AnsiString(Caller));
8956  }
8957  Count++;
8958  }
8959  }
8960  if(LocationNameMultiMap.size() != Count)
8961  {
8962  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8963  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8964  }
8965 // check all entries in both vectors match entries in name multimap
8967 
8968  for(unsigned int x = 0; x < TrackVector.size(); x++)
8969  {
8970  if(TrackElementAt(1364, x).FixedNamedLocationElement)
8971  {
8972  SName = TrackElementAt(1365, x).LocationName;
8973  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8974  if(ErrorString != "")
8975  {
8976  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8977  }
8978  if(SNIt->second != -1 - (int)x)
8979  {
8980  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8981  AnsiString(Caller));
8982  }
8983  }
8984  // check corresponding platform for all Timetable entries that aren't empty
8985  TName = TrackElementAt(1366, x).ActiveTrackElementName;
8986  TIMPair IMPair;
8987  bool FoundFlag = false;
8988  if(TName != "")
8989  {
8990  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
8991  if(FoundFlag)
8992  {
8993  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8995  {
8996  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
8997  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8998  }
8999  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9000  {
9001  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9002  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9003  AnsiString(Caller));
9004  }
9005  }
9006  else
9007  {
9008  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9009  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9010  }
9011  }
9012  }
9013  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9014  {
9015  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9016  {
9017  SName = InactiveTrackElementAt(148, x).LocationName;
9018  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9019  if(ErrorString != "")
9020  {
9021  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9022  }
9023  if(SNIt->second != (int)x)
9024  {
9025  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9026  AnsiString(Caller));
9027  }
9028  }
9029  }
9030  Utilities->CallLogPop(585);
9031 }
9032 
9033 // ---------------------------------------------------------------------------
9034 
9036  AnsiString &ErrorString)
9037 {
9038 /*
9039  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9040  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9041  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9042 */
9043  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9044  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9045  ErrorString = "";
9046  bool FoundFlag = false;
9047  TLocationNameMultiMapIterator SNIterator;
9048  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9049 
9050  if(SNRange.first == SNRange.second)
9051  {
9052  ErrorString = "Error, Name " + LocationName + " not found in map";
9053  Utilities->CallLogPop(586);
9054  return(SNRange.first);
9055  }
9056  else
9057  {
9058  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9059  {
9060  if(SNIterator->second < 0)
9061  {
9062  int TVPos = -1 - SNIterator->second;
9063  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9064  if(TVIt == TrackElement)
9065  {
9066  FoundFlag = true;
9067  Utilities->CallLogPop(587);
9068  return(SNIterator);
9069  }
9070  }
9071  else
9072  {
9073  int ITVPos = SNIterator->second;
9074  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9075  if(ITVIt == TrackElement)
9076  {
9077  FoundFlag = true;
9078  Utilities->CallLogPop(588);
9079  return(SNIterator);
9080  }
9081  }
9082  }
9083  }
9084  if(!FoundFlag)
9085  {
9086  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9087  }
9088  Utilities->CallLogPop(589);
9089  return(SNIterator);
9090 }
9091 
9092 // ---------------------------------------------------------------------------
9093 
9094 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9095 {
9096 /*
9097  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9098  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9099 */
9100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9101  TLocationNameMultiMapEntry LocationNameEntry;
9102 
9103  LocationNameEntry.first = NewName;
9104  LocationNameEntry.second = SNIterator->second;
9105  LocationNameMultiMap.erase(SNIterator);
9106  LocationNameMultiMap.insert(LocationNameEntry);
9107  Utilities->CallLogPop(590);
9108 }
9109 
9110 // ---------------------------------------------------------------------------
9111 
9113 {
9114 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9116  if(Position < 0) // footcrossing
9117  {
9118  int TruePos = -1 - Position;
9119  // new check at v0.2b
9120  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9121  {
9122  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9123  }
9124  Utilities->CallLogPop(591);
9125  return (TrackVector.begin() + TruePos);
9126  }
9127  else
9128  {
9129  // new check at v0.2b
9130  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9131  {
9132  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9133  }
9134  Utilities->CallLogPop(592);
9135  return (InactiveTrackVector.begin() + Position);
9136  }
9137 }
9138 
9139 // ---------------------------------------------------------------------------
9140 
9141 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9142 {
9143 /*
9144  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9145  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9146  LocationNameMultiMap.
9147 */
9148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9149  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9150  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9151 
9152  if(!InactiveTrack2MultiMap.empty())
9153  {
9154  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9155  InactiveTrack2MultiMapIterator++)
9156  {
9157  if(InactiveTrack2MultiMapIterator->second > VecPos)
9158  {
9159  InactiveTrack2MultiMapIterator->second--;
9160  }
9161  // can't be == VecPos as that position erased
9162  }
9163  }
9164  if(!LocationNameMultiMap.empty())
9165  {
9166  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9167  LocationNameMultiMapIterator++)
9168  {
9169  if(LocationNameMultiMapIterator->second < 0)
9170  {
9171  continue; // deal with TrackVectors separately
9172  }
9173  if(LocationNameMultiMapIterator->second > (int)VecPos)
9174  {
9175  LocationNameMultiMapIterator->second--;
9176  }
9177  }
9178  }
9179  Utilities->CallLogPop(593);
9180 }
9181 
9182 // ---------------------------------------------------------------------------
9183 
9184 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9185 {
9186 /*
9187  After an element has been erased from the track vector, all the later elements are moved down one. This function
9188  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9189  LocationNameMultiMap.
9190 */
9191  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9192  TTrackMapIterator TrackMapIterator;
9193  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9194 
9195  if(!TrackMap.empty())
9196  {
9197  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9198  {
9199  if(TrackMapIterator->second > VecPos)
9200  {
9201  TrackMapIterator->second--;
9202  }
9203  // can't be == VecPos as that position erased
9204  }
9205  }
9206  if(!LocationNameMultiMap.empty())
9207  {
9208  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9209  LocationNameMultiMapIterator++)
9210  {
9211  if(LocationNameMultiMapIterator->second >= 0)
9212  {
9213  continue; // deal with InactiveTrackVectors separately
9214  }
9215  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9216  // Val -1 -2 -3 -4 -5 -6 -7 -8
9217  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9218  {
9219  LocationNameMultiMapIterator->second++;
9220  }
9221  }
9222  }
9223  for(unsigned int x = 0; x < TrackVector.size(); x++)
9224  {
9225  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9226  if(TkEl.TrackType == GapJump)
9227  {
9228  // position 0 is the gap
9229  if(TkEl.Conn[0] == int(VecPos))
9230  {
9231  TkEl.Conn[0] = -1; // connected to a deleted gap
9232  continue;
9233  }
9234  if(TkEl.Conn[0] > int(VecPos))
9235  {
9236  TkEl.Conn[0]--;
9237  }
9238  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9239  {
9240  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9241  {
9242  TkEl.Conn[0] = -1;
9243  }
9244  }
9245  }
9246  }
9247  Utilities->CallLogPop(1433);
9248 }
9249 
9250 // ---------------------------------------------------------------------------
9251 
9253 /*
9254  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9255  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9256  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9257 */
9258 {
9259  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9260  LocationNameMultiMap.clear();
9261  TLocationNameMultiMapEntry LocationNameEntry;
9262  TTrackElement TrackElement;
9263 
9264  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9265  {
9266  TrackElement = TrackElementAt(1376, TVPos);
9267  if(TrackElement.FixedNamedLocationElement)
9268  {
9269  LocationNameEntry.first = TrackElement.LocationName;
9270  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9271  LocationNameMultiMap.insert(LocationNameEntry);
9272  }
9273  }
9274 
9275  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9276  {
9277  TrackElement = InactiveTrackElementAt(149, ITVPos);
9278  if(TrackElement.FixedNamedLocationElement)
9279  {
9280  LocationNameEntry.first = TrackElement.LocationName;
9281  LocationNameEntry.second = ITVPos;
9282  LocationNameMultiMap.insert(LocationNameEntry);
9283  }
9284  }
9285  Utilities->CallLogPop(594);
9286 }
9287 
9288 // ---------------------------------------------------------------------------
9289 
9291 // Return true if there is a named location present in the railway
9292 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9293 {
9294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9295  TTrackVectorIterator ITVI;
9296 
9297  if(InactiveTrackVector.empty())
9298  {
9299  Utilities->CallLogPop(1343);
9300  return(false);
9301  }
9302  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9303  {
9304  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9305  {
9306  Utilities->CallLogPop(1404);
9307  return(true);
9308  }
9309  }
9310  Utilities->CallLogPop(1344);
9311  return(false);
9312 }
9313 
9314 // ---------------------------------------------------------------------------
9315 
9317 /*
9318  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9319 */
9320 {
9321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9322 // ResetDistanceElements(6);
9323  for(unsigned int x = 0; x < TrackVector.size(); x++)
9324  {
9325  TTrackElement &TE = TrackElementAt(718, x);
9328  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9329  {
9332  }
9333  }
9334 /* old function
9335  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9336  {
9337  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9338  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9339  }
9340  else
9341  {
9342  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9343  }
9344  }
9345 */
9346  Utilities->CallLogPop(617);
9347 }
9348 
9349 // ---------------------------------------------------------------------------
9350 
9351 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9352 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9353 {
9354  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9355  for(unsigned int x = 0; x < TrackVector.size(); x++)
9356  {
9357  TTrackElement TempElement = TrackElementAt(1377, x);
9358  if(TempElement.Length01 > -1)
9359  {
9360  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9361  }
9362  if(TempElement.Length23 > -1)
9363  {
9364  MarkOneLength(2, TempElement, false, Disp);
9365  }
9366  }
9367  Disp->Update();
9368  Utilities->CallLogPop(618);
9369 }
9370 
9371 // ---------------------------------------------------------------------------
9372 
9373 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9374 /*
9375  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
9376  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9377  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9378  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9379  track as indicated by FirstTrack (true for track01 & false for track23).
9380 */
9381 {
9382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9383  AnsiString((short)FirstTrack));
9384  bool LengthDifferent = false, SpeedDifferent = false;
9385 
9386  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9387  {
9388  Utilities->CallLogPop(619);
9389  return;
9390  }
9391  int EXArray[16][2] =
9392  {{4, 6}, {2, 8}, // horizontal & vertical
9393  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9394  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9395  {1, 9}, {3, 7}}; // forward & reverse diagonals
9396 
9397  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9398  Graphics::TBitmap *Bitmap;
9399 
9400  if(FirstTrack)
9401  {
9402  InLink = TrackElement.Link[0];
9403  OutLink = TrackElement.Link[1];
9404  }
9405  else
9406  {
9407  InLink = TrackElement.Link[2];
9408  OutLink = TrackElement.Link[3];
9409  }
9410  for(int x = 0; x < 16; x++)
9411  {
9412  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9413  {
9414  Index = x;
9415  }
9416  }
9417  if(Index == -1)
9418  {
9419  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9420  }
9421 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9422  the graphic for each of which is different because of the shape of the overbridge. The basic
9423  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9424  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9425  int BrEXArray[24][2] = {
9426  {4,6},{2,8},{1,9},{3,7},
9427  {1,9},{3,7},{1,9},{3,7},
9428  {2,8},{4,6},{2,8},{4,6}
9429 */
9430  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9431  {
9432  if(Index == 1)
9433  {
9434  if(TrackElement.SpeedTag == 49)
9435  {
9436  BrNum = 1 + 16;
9437  }
9438  else if(TrackElement.SpeedTag == 54)
9439  {
9440  BrNum = 8 + 16;
9441  }
9442  else if(TrackElement.SpeedTag == 55)
9443  {
9444  BrNum = 10 + 16;
9445  }
9446  }
9447  else if(Index == 0)
9448  {
9449  if(TrackElement.SpeedTag == 48)
9450  {
9451  BrNum = 0 + 16;
9452  }
9453  else if(TrackElement.SpeedTag == 58)
9454  {
9455  BrNum = 11 + 16;
9456  }
9457  else if(TrackElement.SpeedTag == 59)
9458  {
9459  BrNum = 9 + 16;
9460  }
9461  }
9462  else if(Index == 14)
9463  {
9464  if(TrackElement.SpeedTag == 50)
9465  {
9466  BrNum = 2 + 16;
9467  }
9468  else if(TrackElement.SpeedTag == 52)
9469  {
9470  BrNum = 4 + 16;
9471  }
9472  else if(TrackElement.SpeedTag == 57)
9473  {
9474  BrNum = 6 + 16;
9475  }
9476  }
9477  else if(Index == 15)
9478  {
9479  if(TrackElement.SpeedTag == 51)
9480  {
9481  BrNum = 3 + 16;
9482  }
9483  else if(TrackElement.SpeedTag == 53)
9484  {
9485  BrNum = 7 + 16;
9486  }
9487  else if(TrackElement.SpeedTag == 56)
9488  {
9489  BrNum = 5 + 16;
9490  }
9491  }
9492  }
9493  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9494  {
9495  GrNum = BrNum;
9496  }
9497  else
9498  {
9499  GrNum = Index;
9500  }
9501  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9502  {
9503  if(GrNum > 15) // underbridge
9504  {
9505  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9506  }
9507  else
9508  {
9509  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9510  }
9511  if(TrackElement.SpeedTag == 64)
9512  {
9513  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9514  }
9515  if(TrackElement.SpeedTag == 65)
9516  {
9518  }
9519  if(TrackElement.SpeedTag == 66)
9520  {
9522  }
9523  if(TrackElement.SpeedTag == 67)
9524  {
9526  }
9527  if(TrackElement.SpeedTag == 80)
9528  {
9529  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9530  }
9531  if(TrackElement.SpeedTag == 81)
9532  {
9534  }
9535  if(TrackElement.SpeedTag == 82)
9536  {
9538  }
9539  if(TrackElement.SpeedTag == 83)
9540  {
9542  }
9543  if(TrackElement.SpeedTag == 84)
9544  {
9546  }
9547  if(TrackElement.SpeedTag == 85)
9548  {
9550  }
9551  if(TrackElement.SpeedTag == 86)
9552  {
9554  }
9555  if(TrackElement.SpeedTag == 87)
9556  {
9558  }
9559  if(TrackElement.SpeedTag == 129)
9560  {
9561  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9562  }
9563  if(TrackElement.SpeedTag == 130)
9564  {
9566  }
9567  }
9568 
9569  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9570  {
9571  if(GrNum > 15) // underbridge
9572  {
9573  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9574  }
9575  else
9576  {
9577  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9578  }
9579  if(TrackElement.SpeedTag == 64)
9580  {
9581  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9582  }
9583  if(TrackElement.SpeedTag == 65)
9584  {
9585  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9586  }
9587  if(TrackElement.SpeedTag == 66)
9588  {
9589  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9590  }
9591  if(TrackElement.SpeedTag == 67)
9592  {
9593  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9594  }
9595  if(TrackElement.SpeedTag == 80)
9596  {
9597  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9598  }
9599  if(TrackElement.SpeedTag == 81)
9600  {
9601  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9602  }
9603  if(TrackElement.SpeedTag == 82)
9604  {
9605  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9606  }
9607  if(TrackElement.SpeedTag == 83)
9608  {
9609  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9610  }
9611  if(TrackElement.SpeedTag == 84)
9612  {
9613  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9614  }
9615  if(TrackElement.SpeedTag == 85)
9616  {
9617  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9618  }
9619  if(TrackElement.SpeedTag == 86)
9620  {
9621  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9622  }
9623  if(TrackElement.SpeedTag == 87)
9624  {
9625  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9626  }
9627  if(TrackElement.SpeedTag == 129)
9628  {
9629  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9630  }
9631  if(TrackElement.SpeedTag == 130)
9632  {
9633  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9634  }
9635  }
9636 
9637  else // SpeedDifferent only: red - use non sig graphics
9638  {
9639  if(GrNum > 15) // underbridge
9640  {
9641  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9642  }
9643  else
9644  {
9645  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9646  }
9647  if(TrackElement.SpeedTag == 64)
9648  {
9649  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9650  }
9651  if(TrackElement.SpeedTag == 65)
9652  {
9654  }
9655  if(TrackElement.SpeedTag == 66)
9656  {
9658  }
9659  if(TrackElement.SpeedTag == 67)
9660  {
9662  }
9663  if(TrackElement.SpeedTag == 80)
9664  {
9665  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9666  }
9667  if(TrackElement.SpeedTag == 81)
9668  {
9670  }
9671  if(TrackElement.SpeedTag == 82)
9672  {
9674  }
9675  if(TrackElement.SpeedTag == 83)
9676  {
9678  }
9679  if(TrackElement.SpeedTag == 84)
9680  {
9682  }
9683  if(TrackElement.SpeedTag == 85)
9684  {
9686  }
9687  if(TrackElement.SpeedTag == 86)
9688  {
9690  }
9691  if(TrackElement.SpeedTag == 87)
9692  {
9694  }
9695  if(TrackElement.SpeedTag == 129)
9696  {
9697  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9698  }
9699  if(TrackElement.SpeedTag == 130)
9700  {
9702  }
9703  }
9704  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9705  Utilities->CallLogPop(620);
9706 }
9707 
9708 // ---------------------------------------------------------------------------
9709 
9710 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9711 /* FirstTrack = LinkPos's 0 & 1
9712  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9713 */
9714 {
9715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9716  AnsiString((short)FirstTrack));
9717  LengthDifferent = false;
9718  SpeedDifferent = false;
9719  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9720  {
9721  if(TrackElement.Length01 != DefaultTrackLength)
9722  {
9723  LengthDifferent = true;
9724  }
9725  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9726  {
9727  SpeedDifferent = true;
9728  }
9729  if(LengthDifferent || SpeedDifferent)
9730  {
9731  Utilities->CallLogPop(625);
9732  return(false);
9733  }
9734  Utilities->CallLogPop(626);
9735  return(true);
9736  }
9737 
9738  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9739  {
9740  if(TrackElement.Length23 != DefaultTrackLength)
9741  {
9742  LengthDifferent = true;
9743  }
9744  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9745  {
9746  SpeedDifferent = true;
9747  }
9748  if(LengthDifferent || SpeedDifferent)
9749  {
9750  Utilities->CallLogPop(627);
9751  return(false);
9752  }
9753  Utilities->CallLogPop(628);
9754  return(true);
9755  }
9756 
9757  else // any other 1 track element, including platforms being present
9758  {
9759  if(TrackElement.Length01 != DefaultTrackLength)
9760  {
9761  LengthDifferent = true;
9762  }
9763  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9764  {
9765  SpeedDifferent = true;
9766  }
9767  if(LengthDifferent || SpeedDifferent)
9768  {
9769  Utilities->CallLogPop(629);
9770  return(false);
9771  }
9772  Utilities->CallLogPop(630);
9773  return(true);
9774  }
9775 }
9776 
9777 // ---------------------------------------------------------------------------
9778 
9779 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9780 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9781 {
9782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9783  AnsiString(VLoc));
9784  bool FoundFlag;
9785  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9786 
9787  if(!FoundFlag)
9788  {
9789  Utilities->CallLogPop(633);
9790  return(false);
9791  }
9792  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9793  {
9794  Utilities->CallLogPop(634);
9795  return(true); // only need to check first since if second is a platform the the first must be too
9796  }
9797  else
9798  {
9799  Utilities->CallLogPop(635);
9800  return(false);
9801  }
9802 }
9803 
9804 // ---------------------------------------------------------------------------
9805 
9806 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9807 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9808 {
9809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9810  AnsiString(VLoc));
9811  bool FoundFlag;
9812  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9813 
9814  if(!FoundFlag)
9815  {
9816  Utilities->CallLogPop(636);
9817  return(false);
9818  }
9820  {
9821  Utilities->CallLogPop(637);
9822  return(true); // only need to check first since only one used for NamedNonStationLocations
9823  }
9824  else
9825  {
9826  Utilities->CallLogPop(638);
9827  return(false);
9828  }
9829 }
9830 
9831 // ---------------------------------------------------------------------------
9832 
9834 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9835  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9836  the front of train stop points for each direction.
9837  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9838  end (unless buffers at one or both ends in which case stop points are the end elements).
9839  Note that for a single element the stop point is the element itself (formula doesn't apply).
9840  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9841  repeating the procedure for every element. At the end all unused values are returned to -1.
9842  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9843 */
9844 {
9845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9846  TTrackElement TempElement, StartElement;
9847  AnsiString TempName;
9848  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9849  bool ForwardSet, ReverseSet;
9850 
9851  for(unsigned int x = 0; x < TrackVector.size(); x++)
9852  {
9855  }
9856  for(unsigned int x = 0; x < TrackVector.size(); x++)
9857  {
9858  ForwardSet = false;
9859  ReverseSet = false;
9860  TempElement = TrackElementAt(1380, x);
9861  VecPos = x;
9862  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9863  // 2nd condition incl so don't re-examine elements with stop links set to 5
9864  {
9865  TempName = TempElement.ActiveTrackElementName;
9866  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9867  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9868  // an element linked at both ends where both links are also named elements
9869  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9870  {
9871  continue; // looking for an end element so skip this one
9872  }
9873  else // reached one end
9874  {
9875  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9876  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9877  // single named element linked at both ends
9878  {
9879  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9880  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9881  continue;
9882  }
9883  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9884  // single named buffer element (LinkPos 1 is the non-buffer end)
9885  {
9886  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9887  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9888  continue;
9889  }
9890  else
9891  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9892  // and platforms always on straight (conns 0 & 1) section of points
9893  {
9894  for(int y = 0; y < 2; y++)
9895  {
9896  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9897  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9898 /* TTrackElement Temp1 = TempElement;
9899  ***********New section, compiles but not checked - does bit below need to be else if?
9900  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9901  {
9902  //search along Dir direction until find other end, skip if Dir facing buffer end
9903  int NewDir = Dir;
9904  int NewVecPos;
9905  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9906  {
9907  NewVecPos = Temp1.Conn[NewDir];
9908  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9909  Temp1 = TrackElementAt(601, NewVecPos);
9910  }
9911  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9912  {
9913  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9914  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9915  }
9916  }
9917  ***************
9918 */
9919  // end may be linked at both ends but only one link named, or buffer with linked element named
9920  // if a buffer then the named linkpos has to be 1
9921  // already dealt with all types of single element so at least 2 linked named element
9922  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9923  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
9924  {
9925  StartElement = TempElement;
9926  StartVecPos = VecPos;
9927  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9928  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9929  EntryPos = 1 - Dir;
9930  StartEntryPos = 1 - Dir;
9931  Count = 1;
9932  // work along named elements until find the other end
9933  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9934  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9935  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9936  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9937  // all stop link pos's are set to 5
9938  {
9939  VecPos = TempElement.Conn[1 - EntryPos];
9940  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9941  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9942  EntryPos = TempEntryPos;
9943  Count++;
9944  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9945  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9946  }
9947  // here when reached other end, maybe buffers, continuation or last named linked element
9948  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9949  // terminal station, set end elements as stop elements
9950  {
9951  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9952  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9953  continue;
9954  }
9955  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9956  // terminal station, set end elements as stop elements
9957  {
9958  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9959  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9960  continue;
9961  }
9962  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9963  // NonStationLocation so set end elements as stop elements
9964  {
9965  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9966  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9967  continue;
9968  }
9969  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9970  ForwardNumber = ((Count + 1) / 2) + 1;
9971  ReverseNumber = (Count - ForwardNumber) + 1;
9972  Count = 1; // starting value
9973  EntryPos = 1 - Dir;
9974  TempElement = StartElement;
9975  VecPos = StartVecPos;
9976  if(Count == ForwardNumber)
9977  {
9978  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9979  ForwardSet = true;
9980  }
9981  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9982  {
9983  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9984  ReverseSet = true;
9985  }
9986  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9987  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9988  {
9989  VecPos = TempElement.Conn[1 - EntryPos];
9990  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9991  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9992  EntryPos = TempEntryPos;
9993  Count++;
9994  if(Count == ForwardNumber)
9995  {
9996  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9997  ForwardSet = true;
9998  }
9999  if(Count == ReverseNumber)
10000  {
10001  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10002  ReverseSet = true;
10003  }
10004  }
10005  }
10006  }
10007  }
10008  }
10009  }
10010  }
10011  for(unsigned int x = 0; x < TrackVector.size(); x++)
10012  {
10013  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10014  {
10016  }
10017  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10018  {
10020  }
10021  }
10022  Utilities->CallLogPop(639);
10023 }
10024 
10025 // ---------------------------------------------------------------------------
10026 
10027 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10028 {
10029  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10030  TTrackElement Next;
10031 
10033  while(ReturnNextInactiveTrackElement(1, Next))
10034  {
10035  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10036  {
10037  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10038  // need striped graphics
10039  {
10040  if(Next.SpeedTag == 76)
10041  {
10042  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10043  }
10044  else if(Next.SpeedTag == 77)
10045  {
10046  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10047  }
10048  else if(Next.SpeedTag == 78)
10049  {
10050  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10051  }
10052  else if(Next.SpeedTag == 79)
10053  {
10054  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10055  }
10056  else if(Next.SpeedTag == 96)
10057  {
10058  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10059  }
10060  else if(Next.SpeedTag == 131)
10061  {
10062  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10063  }
10064  }
10065  else
10066  {
10067  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10068  }
10069  }
10070  }
10071 
10072  NextTrackElementPtr = TrackVector.begin();
10073  while(ReturnNextTrackElement(1, Next))
10074  {
10075  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10076  {
10077  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10078  {
10079  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10080  {
10081  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10082  }
10083  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10084  {
10085  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10086  }
10087  }
10088  else
10089  {
10090  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10091  }
10092  }
10093  }
10094  Disp->Update();
10095  Utilities->CallLogPop(640);
10096 }
10097 
10098 // ---------------------------------------------------------------------------
10099 
10100 void TTrack::PlotSmallRedGap(int Caller)
10101 {
10102  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10104  Utilities->CallLogPop(1346);
10105 }
10106 
10107 // ---------------------------------------------------------------------------
10108 
10109 void TTrack::TrackClear(int Caller)
10110 {
10111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10112  TrackVector.clear();
10113  InactiveTrackVector.clear();
10114  TrackMap.clear();
10116  if(TextHandler->TextVector.size() == 0)
10117  {
10118  Display->DisplayOffsetH = 0;
10119  Display->DisplayOffsetV = 0;
10126  HLocMin = 2000000000;
10127  HLocMax = -2000000000;
10128  VLocMin = 2000000000;
10129  VLocMax = -2000000000;
10130  }
10131  else
10132  {
10133  CalcHLocMinEtc(4);
10134  }
10135  Utilities->CallLogPop(1347);
10136 }
10137 
10138 // ---------------------------------------------------------------------------
10139 
10140 void TTrack::CalcHLocMinEtc(int Caller)
10141 {
10142  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10143  HLocMin = 2000000000;
10144  VLocMin = 2000000000;
10145  HLocMax = -2000000000;
10146  VLocMax = -2000000000;
10147  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10148  {
10149  if(TrackElementAt(1385, x).SpeedTag == 0)
10150  {
10151  continue; // skip erase elements or would interfere with Min & Max values
10152  }
10153  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10154  {
10155  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10156  }
10157  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10158  {
10159  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10160  }
10161  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10162  {
10163  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10164  }
10165  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10166  {
10167  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10168  }
10169  }
10170  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10171  {
10172  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10173  {
10174  continue; // shouldn't be any inactive erase elements but include anyway
10175  }
10176  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10177  {
10178  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10179  }
10180  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10181  {
10182  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10183  }
10184  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10185  {
10186  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10187  }
10188  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10189  {
10190  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10191  }
10192  }
10193  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10194  {
10195 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10196  will fail as x will exceed the maximum value
10197  if(TextHandler->TextPtrAt(, x)->TextString == "")
10198  {
10199  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10200  }
10201 */
10202  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10203  if((TextH / 16) - 1 < HLocMin)
10204  {
10205  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10206  }
10207  if((TextH / 16) + 1 > HLocMax)
10208  {
10209  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10210  }
10211  if((TextV / 16) - 1 < VLocMin)
10212  {
10213  VLocMin = (TextV / 16) - 1;
10214  }
10215  if((TextV / 16) + 1 > VLocMax)
10216  {
10217  VLocMax = (TextV / 16) + 1;
10218  }
10219  }
10220  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10221  {
10222  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10223  {
10224  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10225  }
10226  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10227  {
10228  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10229  }
10230  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10231  {
10232  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10233  }
10234  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10235  {
10236  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10237  }
10238  }
10239 
10240  Utilities->CallLogPop(641);
10241 }
10242 
10243 // ---------------------------------------------------------------------------
10244 
10245 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10246  bool &UserGraphicFoundFlag)
10247 {
10248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10249  TUserGraphicVector::iterator UserGraphicPtr;
10250 
10251  UserGraphicFoundFlag = false;
10252  if(!UserGraphicVector.empty())
10253  {
10254  int x = UserGraphicVector.size();
10255  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10256  {
10257  x--;
10258  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10259  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10260  {
10261  UserGraphicItem = x;
10262  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10263  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10264  UserGraphicFoundFlag = true;
10265  Utilities->CallLogPop(2177);
10266  return;
10267  } // if ....
10268 
10269  } // for UserGraphicPtr...
10270  } // if !UserGraphicVector...
10271 
10272  Utilities->CallLogPop(2197);
10273 }
10274 
10275 // ---------------------------------------------------------------------------
10276 
10278 {
10279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10280  TrackElement.LogTrack(11));
10281  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10282  int SpeedTag = TrackElement.SpeedTag;
10283 
10284  if(SpeedTag < 1)
10285  {
10286  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10287  }
10288  switch(SpeedTag)
10289  {
10290  case 76: // t platform
10291  GraphicOutput = RailGraphics->gl76Striped;
10292  break;
10293 
10294  case 77: // h platform
10295  GraphicOutput = RailGraphics->bm77Striped;
10296  break;
10297 
10298  case 78: // v platform
10299  GraphicOutput = RailGraphics->bm78Striped;
10300  break;
10301 
10302  case 79: // r platform
10303  GraphicOutput = RailGraphics->gl79Striped;
10304  break;
10305 
10306  case 96: // concourse
10307  GraphicOutput = RailGraphics->ConcourseStriped;
10308  break;
10309 
10310  case 129: // v footbridge
10311  GraphicOutput = RailGraphics->gl129Striped;
10312  break;
10313 
10314  case 130: // h footbridge
10315  GraphicOutput = RailGraphics->gl130Striped;
10316  break;
10317 
10318  case 131: // non-station named loc
10319  GraphicOutput = RailGraphics->bmNameStriped;
10320  break;
10321 
10322  case 145: // v u'pass
10323  GraphicOutput = RailGraphics->gl145Striped;
10324  break;
10325 
10326  case 146: // h u'pass
10327  GraphicOutput = RailGraphics->gl146Striped;
10328  break;
10329 
10330  default:
10331  GraphicOutput = TrackElement.GraphicPtr;
10332  break;
10333  }
10334  Utilities->CallLogPop(642);
10335  return(GraphicOutput);
10336 }
10337 
10338 // ---------------------------------------------------------------------------
10339 
10341 {
10342  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10343  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10344  {
10345  Utilities->CallLogPop(2281);
10346  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10347  }
10348  Utilities->CallLogPop(643);
10349  return(TrackVector.at(At));
10350 }
10351 
10352 // ---------------------------------------------------------------------------
10353 
10355 {
10356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10357  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10358  {
10359  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10360  " in InactiveTrackElementAt");
10361  }
10362  Utilities->CallLogPop(644);
10363  return(InactiveTrackVector.at(At));
10364 }
10365 
10366 // ---------------------------------------------------------------------------
10367 
10368 bool TTrack::BlankElementAt(int Caller, int At) const
10369 {
10370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10371  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10372  {
10373  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10374  }
10375  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10376  {
10377  Utilities->CallLogPop(645);
10378  return(true);
10379  }
10380  else
10381  {
10382  Utilities->CallLogPop(646);
10383  return(false);
10384  }
10385 }
10386 
10387 // ---------------------------------------------------------------------------
10388 
10389 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10390 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10391  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10392  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10393  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10394  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10395 */
10396 {
10397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10398  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10399  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10400  TLocationNameMultiMapIterator SNIterator;
10401  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10402 
10403  if(SNRange.first == SNRange.second)
10404  {
10405  Utilities->CallLogPop(972);
10406  return(false); // should have been caught earlier but include for completeness
10407  }
10408  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10409  {
10410  if(SNIterator->second < 0)
10411  {
10412  continue; // exclude footcrossings
10413  }
10414  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10415  if(InactiveElement.TrackType == Concourse)
10416  {
10417  continue; // only interested in locations where ActiveTrackElementName may be set
10418  }
10419  THVPair HVPair;
10420  HVPair.first = InactiveElement.HLoc;
10421  HVPair.second = InactiveElement.VLoc;
10422  if(TrackMap.find(HVPair) == TrackMap.end())
10423  {
10424  throw Exception
10425  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10426  }
10427  int TVPos = TrackMap.find(HVPair)->second;
10428  FirstNamedElement = TrackElementAt(560, TVPos);
10429  // first check linked on both sides, skip the check if not
10430  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10431  {
10432  continue;
10433  }
10434  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10435  // ActiveTrackElementNames are points and excluding trailing connections for points
10436  FirstNamedExitPos = 0;
10437  {
10438  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10439  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10440  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10441  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10442  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10443  {
10444  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10445  {
10446  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10447  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10448  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10449  // success, now check FirstNamedElement link not trailing points & if so all OK
10450  {
10451  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10452  {
10453  Utilities->CallLogPop(1002);
10454  return(true);
10455  }
10456  }
10457  }
10458  }
10459  }
10460  // failed, try link 1
10461  FirstNamedExitPos = 1;
10462  {
10463  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10464  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10465  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10466  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10467  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10468  {
10469  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10470  {
10471  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10472  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10473  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10474  // success, now check FirstNamedElement link not trailing points & if so all OK
10475  {
10476  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10477  {
10478  Utilities->CallLogPop(1003);
10479  return(true);
10480  }
10481  }
10482  }
10483  }
10484  }
10485  }
10486  Utilities->CallLogPop(1004);
10487  return(false);
10488 }
10489 
10490 // ---------------------------------------------------------------------------
10491 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10492  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10493 // for success need two linked named location elements, so that one element of each train can be at the location
10494 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10495 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10496 // the two trains will occupy these 4 elements
10497 // All are track vector positions, all but the input being references and set within the function.
10498 {
10499 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10500  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10501  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10502  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10503  splitting.
10504 */
10505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10506  AnsiString(FirstNamedElementPos));
10507  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10508  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10509 
10510  SecondNamedElementPos = -1;
10511  FirstNamedLinkedElementPos = -1;
10512  SecondNamedLinkedElementPos = -1;
10513  TLocationNameMultiMapIterator SNIterator;
10514  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10515 
10516  if(SNRange.first == SNRange.second) // i.e. location name not in map
10517  {
10518  Utilities->CallLogPop(1005);
10519  return(false); // should have been caught earlier but include for completeness
10520  }
10521  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10522  {
10523  if(SNIterator->second < 0)
10524  {
10525  continue; // exclude footcrossings
10526  }
10527  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10528  if(InactiveElement.TrackType == Concourse)
10529  {
10530  continue; // only interested in locations where ActiveTrackElementName may be set
10531  }
10532  THVPair HVPair;
10533  HVPair.first = InactiveElement.HLoc;
10534  HVPair.second = InactiveElement.VLoc;
10535  if(TrackMap.find(HVPair) == TrackMap.end())
10536  {
10537  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10538  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10539  // then it won't be found in TrackMap but it's still legitimate.
10540  {
10541  continue;
10542  }
10543  else // for anything else throw the error
10544  {
10545  throw Exception
10546  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10547  );
10548  }
10549  }
10550  int TVPos = TrackMap.find(HVPair)->second;
10551  if(TVPos != FirstNamedElementPos)
10552  {
10553  continue; // looking for an exact match
10554  }
10555  FirstNamedElement = TrackElementAt(567, TVPos);
10556  // first check linked on both sides, skip the check if not
10557  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10558  {
10559  continue;
10560  }
10561  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10562  // ActiveTrackElementNames are points and excluding trailing connections for points
10563  FirstNamedExitPos = 0;
10564  {
10565  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10566  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10567  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10568  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10569  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10570  {
10571  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10572  {
10573  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10574  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10575  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10576  // success, now check FirstNamedElement link not trailing points & if so all OK
10577  {
10578  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10579  {
10580  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10581  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10582  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10583  Utilities->CallLogPop(1006);
10584  return(true);
10585  }
10586  }
10587  }
10588  }
10589  }
10590  // failed, try link 1
10591  FirstNamedExitPos = 1;
10592  {
10593  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10594  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10595  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10596  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10597  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10598  {
10599  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10600  {
10601  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10602  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10603  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10604  // success, now check FirstNamedElement link not trailing points & if so all OK
10605  {
10606  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10607  {
10608  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10609  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10610  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10611  Utilities->CallLogPop(1007);
10612  return(true);
10613  }
10614  }
10615  }
10616  }
10617  }
10618  }
10619  Utilities->CallLogPop(1008);
10620  return(false);
10621 }
10622 
10623 // ---------------------------------------------------------------------------
10624 
10625 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10626 {
10627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10628  TLocationNameMultiMapIterator SNIterator;
10629  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10630 
10631  if(SNRange.first != SNRange.second)
10632  {
10633  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10634  {
10635  if(SNIterator->second < 0)
10636  {
10637  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10638  }
10639  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10640  SNIterator->second).TrackType == NamedNonStationLocation))
10641  {
10642  Utilities->CallLogPop(1121);
10643  return(true);
10644  }
10645  }
10646  }
10647  Utilities->CallLogPop(848);
10648  return(false);
10649 }
10650 
10651 // ---------------------------------------------------------------------------
10652 
10653 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10654 {
10655 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10657  "," + AnsiString(SpeedTag));
10658  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10659  {
10660  Utilities->CallLogPop(949);
10661  return(false);
10662  }
10663  bool FoundFlag;
10664  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10665 
10666  if(!FoundFlag)
10667  {
10668  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10669  }
10670  TTrackElement IAElement;
10671 
10672  if(SpeedTag == 68) // top sig
10673  {
10674  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10675  {
10676  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10677  {
10678  IAElement = InactiveTrackElementAt(50, IMPair.first);
10679  }
10680  else
10681  {
10682  IAElement = InactiveTrackElementAt(51, IMPair.second);
10683  }
10684  if(IAElement.LocationName == "")
10685  {
10686 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10687  SignalPlatformGraphic = RailGraphics->gl76Striped;
10688  }
10689  else
10690  {
10691 // SignalPlatformGraphic = RailGraphics->Plat68;
10692  SignalPlatformGraphic = RailGraphics->gl76;
10693  }
10694  Utilities->CallLogPop(950);
10695  return(true);
10696  }
10697  }
10698  else if(SpeedTag == 69) // bot sig
10699  {
10700  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10701  {
10702  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10703  {
10704  IAElement = InactiveTrackElementAt(77, IMPair.first);
10705  }
10706  else
10707  {
10708  IAElement = InactiveTrackElementAt(78, IMPair.second);
10709  }
10710  if(IAElement.LocationName == "")
10711  {
10712 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10713  SignalPlatformGraphic = RailGraphics->bm77Striped;
10714  }
10715  else
10716  {
10717 // SignalPlatformGraphic = RailGraphics->Plat69;
10718  SignalPlatformGraphic = RailGraphics->bm77;
10719  }
10720  Utilities->CallLogPop(951);
10721  return(true);
10722  }
10723  }
10724  else if(SpeedTag == 70) // left sig
10725  {
10726  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10727  {
10728  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10729  {
10730  IAElement = InactiveTrackElementAt(55, IMPair.first);
10731  }
10732  else
10733  {
10734  IAElement = InactiveTrackElementAt(82, IMPair.second);
10735  }
10736  if(IAElement.LocationName == "")
10737  {
10738 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10739  SignalPlatformGraphic = RailGraphics->bm78Striped;
10740  }
10741  else
10742  {
10743 // SignalPlatformGraphic = RailGraphics->Plat70;
10744  SignalPlatformGraphic = RailGraphics->bm78;
10745  }
10746  Utilities->CallLogPop(952);
10747  return(true);
10748  }
10749  }
10750  else if(SpeedTag == 71) // right sig
10751  {
10752  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10753  {
10754  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10755  {
10756  IAElement = InactiveTrackElementAt(85, IMPair.first);
10757  }
10758  else
10759  {
10760  IAElement = InactiveTrackElementAt(86, IMPair.second);
10761  }
10762  if(IAElement.LocationName == "")
10763  {
10764 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10765  SignalPlatformGraphic = RailGraphics->gl79Striped;
10766  }
10767  else
10768  {
10769 // SignalPlatformGraphic = RailGraphics->Plat71;
10770  SignalPlatformGraphic = RailGraphics->gl79;
10771  }
10772  Utilities->CallLogPop(953);
10773  return(true);
10774  }
10775  }
10776  Utilities->CallLogPop(954);
10777  return(false);
10778 }
10779 
10780 // ---------------------------------------------------------------------------
10781 
10782 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10783 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10784 // false if not, if NextPos == -1, or if only own train on the track
10785 {
10786  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10787  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10788  if(NextEntryPos < 0)
10789  {
10790  Utilities->CallLogPop(1348);
10791  return(false);
10792  }
10793  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10794 
10795  if(TrackElement.TrackType != Bridge)
10796  {
10797  Utilities->CallLogPop(1349);
10798  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10799  }
10800 // bridge if reach here
10801  if(NextEntryPos > 1)
10802  {
10803  Utilities->CallLogPop(1350);
10804  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10805  }
10806  else
10807  {
10808  Utilities->CallLogPop(1351);
10809  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10810  }
10811 }
10812 
10813 // ---------------------------------------------------------------------------
10814 
10816 {
10817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10818  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10819  {
10820  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10821  }
10822  Utilities->CallLogPop(1483);
10823  return(SelectVector.at(At));
10824 }
10825 
10826 // ---------------------------------------------------------------------------
10827 
10828 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
10829 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
10830 {
10831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
10832  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
10833  bool FoundFlag = false;
10834  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
10835  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
10836 
10837  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
10838  Utilities->CallLogPop(1538);
10839  return(FoundFlag);
10840 }
10841 
10842 // ---------------------------------------------------------------------------
10843 
10844 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
10845 {
10846 // return true if find an inactive element called 'Name'
10847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
10848  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
10849  bool FoundFlag = false;
10850 
10851  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10852  {
10853  if(InactiveTrackElementAt(158, x).LocationName == Name)
10854  {
10855  FoundFlag = true;
10856  int V = InactiveTrackElementAt(159, x).VLoc;
10857  int H = InactiveTrackElementAt(160, x).HLoc;
10858  if(V > VLocHi)
10859  {
10860  VLocHi = V;
10861  }
10862  if(V < VLocLo)
10863  {
10864  VLocLo = V;
10865  }
10866  if(H < HLoc)
10867  {
10868  HLoc = H;
10869  }
10870  }
10871  }
10872  if(FoundFlag)
10873  {
10874  VPosHi = 16 * VLocHi;
10875  VPosLo = 16 * VLocLo;
10876  HPos = 16 * HLoc;
10877  Utilities->CallLogPop(1562);
10878  return(true);
10879  }
10880  else
10881  {
10882  Utilities->CallLogPop(1563);
10883  return(false);
10884  }
10885 }
10886 
10887 // ---------------------------------------------------------------------------
10888 
10889 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10890 {
10891 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10892 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10893  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10894  AnsiString(EndTVPosition));
10895  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10896  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10897 
10898 // get H & V values for the element adjacent to Link[0] & Link[1]
10899  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10900  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10901  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10902  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10903 
10904 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10905  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10906  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10907  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10908  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10909 
10910  if(Link0Squares <= Link1Squares)
10911  {
10912  Utilities->CallLogPop(1851);
10913  return(0);
10914  }
10915  else
10916  {
10917  Utilities->CallLogPop(1852);
10918  return(1);
10919  }
10920 }
10921 
10922 // ---------------------------------------------------------------------------
10923 
10924 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
10925 {
10926  // element can be points or any other type
10927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
10928  AnsiString(LinkPos));
10929  Derail = false;
10930  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
10931 
10932  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
10933  {
10934  if(TE.Attribute == 0)
10935  {
10936  Utilities->CallLogPop(663);
10937  return(1); // Att == 0 & ExitPos == 1 represent straight
10938  }
10939  else
10940  {
10941  Utilities->CallLogPop(664);
10942  return(3); // Att == 1 & ExitPos == 3 represent diverging
10943  }
10944  }
10945  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
10946  {
10947  if((LinkPos == 1) && (TE.Attribute == 0))
10948  {
10949  Utilities->CallLogPop(665);
10950  return(0); // Att == 0 represents straight
10951  }
10952  else if(LinkPos == 1)
10953  {
10954  Derail = true;
10955  Utilities->CallLogPop(666);
10956  return(0);
10957  }
10958  else if((LinkPos == 3) && (TE.Attribute == 1))
10959  {
10960  Utilities->CallLogPop(667);
10961  return(0);
10962  }
10963  else if(LinkPos == 3)
10964  {
10965  Derail = true;
10966  Utilities->CallLogPop(668);
10967  return(0);
10968  }
10969  }
10970  else if(LinkPos == 0)
10971  {
10972  Utilities->CallLogPop(669);
10973  return(1);
10974  }
10975  else if(LinkPos == 1)
10976  {
10977  Utilities->CallLogPop(670);
10978  return(0);
10979  }
10980  else if(LinkPos == 2)
10981  {
10982  Utilities->CallLogPop(671);
10983  return(3);
10984  }
10985  else if(LinkPos == 3)
10986  {
10987  Utilities->CallLogPop(672);
10988  return(2);
10989  }
10990  throw Exception("Error, failure in GetExitPos"); // should never reach here
10991 }
10992 
10993 // ----------------------------------------------------------------------------
10994 
10996 {
10997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
10998  LCVector.clear();
10999  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11000  {
11001  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11002  {
11003  LCVector.push_back(x);
11004  }
11005  }
11006  Utilities->CallLogPop(1931);
11007  return;
11008 }
11009 
11010 // ---------------------------------------------------------------------------
11011 
11012 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11013 /*
11014  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11015  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11016  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11017  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11018 */
11019 {
11020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11021  AnsiString(Link));
11022  bool FoundFlag;
11023 
11024  TrainID = -1;
11025  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11026 
11027  if(!FoundFlag)
11028  {
11029  Utilities->CallLogPop(2001);
11030  return(false);
11031  }
11032  TTrackElement TE = TrackElementAt(882, VecPos);
11033 
11034  TrainID = TE.TrainIDOnElement;
11035  if(TE.TrackType == Bridge)
11036  {
11037  if(TE.TrainIDOnElement > -1)
11038  {
11039  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11040  {
11041  TrainID = TE.TrainIDOnBridgeTrackPos01;
11042  }
11043  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11044  {
11045  TrainID = TE.TrainIDOnBridgeTrackPos23;
11046  }
11047  else
11048  {
11049  TrainID = -1; // shouldn't ever reach here but be safe
11050  }
11051  }
11052  }
11053  if(TrainID == -1)
11054  {
11055  Utilities->CallLogPop(2002);
11056  return(false);
11057  }
11058 // now get the train
11059  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11060 
11061  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11062  {
11063  Utilities->CallLogPop(2003);
11064  return(true);
11065  }
11066  TrainID = -1;
11067  Utilities->CallLogPop(2004);
11068  return(false);
11069 }
11070 
11071 // ---------------------------------------------------------------------------
11072 
11073 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11074 /* New at v1.2.0
11075  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11076  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11077  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11078  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11079  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11080  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11081  Each of these is examined in turn for each route element in the relevant position.
11082 */
11083 {
11084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11085  "," + AnsiString(DiagonalLinkNumber));
11086  TrainID = -1;
11087  TPrefDirElement TempPrefDirElement;
11088  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11089 
11090  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11091  {
11092  Utilities->CallLogPop(2027);
11093  return(true);
11094  }
11095  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11096  {
11097  Utilities->CallLogPop(2028);
11098  return(true);
11099  }
11100  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11101  {
11102  Utilities->CallLogPop(2029);
11103  return(true);
11104  }
11105  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11106  {
11107  Utilities->CallLogPop(2030);
11108  return(true);
11109  }
11110  Utilities->CallLogPop(2031);
11111  return(false);
11112 }
11113 
11114 // ---------------------------------------------------------------------------
11115 
11116 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11117 {
11118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11119  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11120  TUserGraphicItem UGI;
11121  AnsiString JustFileName = "";
11122 
11123  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11124  {
11125  UGI = UserGraphicVectorAt(17, x);
11126  int LastDelim = UGI.FileName.LastDelimiter('\\');
11127  if(LastDelim == 0) // can't find it so skip this item
11128  {
11129  continue;
11130  }
11131  else
11132  {
11133  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11134  }
11135  Utilities->SaveFileString(VecFile, JustFileName);
11136  Utilities->SaveFileInt(VecFile, UGI.HPos);
11137  Utilities->SaveFileInt(VecFile, UGI.VPos);
11138  }
11139  Utilities->CallLogPop(2178);
11140 }
11141 
11142 // ---------------------------------------------------------------------------
11143 
11144 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11145 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11146 {
11147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11148  int NumPlats = 0;
11149  TTrackElement TempElement;
11150  int TempInt;
11151 
11152  typedef std::list<int> TNamePosList;
11153  TNamePosList NamePosList;
11154  typedef TNamePosList::iterator TNPLIt;
11155  TNPLIt NPLIt;
11156  typedef std::list<int> TOnePlatList;
11157  TOnePlatList OnePlatList;
11158  typedef TOnePlatList::iterator TOPLIt;
11159  TOPLIt OPLIt;
11160 
11161  NamePosList.clear();
11162  OnePlatList.clear();
11163  for(unsigned int x = 0; x < TrackVector.size(); x++)
11164  {
11165  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11166  {
11167  NamePosList.push_back(x);
11168  }
11169  }
11170  //NamePosList complete
11171 
11172  if(!NamePosList.empty()) //first value for the loop examination
11173  {
11174  OnePlatList.push_back(NamePosList.back());
11175  NamePosList.pop_back(); //erase from NPV as done with it here
11176  }
11177  while(!OnePlatList.empty()) //loop to examine all linked elements
11178  {
11179  TempInt = OnePlatList.front();
11180  TempElement = TrackElementAt(989, TempInt);
11181 
11182  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11183  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11184  {
11185  OnePlatList.push_back(TempElement.Conn[0]);
11186  NamePosList.erase(NPLIt);
11187  }
11188  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11189  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11190  {
11191  OnePlatList.push_back(TempElement.Conn[1]);
11192  NamePosList.erase(NPLIt);
11193  }
11194  //here when loaded any connecting links into OnePlatList, so can erase the front element
11195  OnePlatList.erase(OnePlatList.begin());
11196  if(OnePlatList.empty())
11197  {
11198  NumPlats++; //finished with current linked elements so can increment NumPlats
11199  if(!NamePosList.empty())
11200  {
11201  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11202  NamePosList.pop_back(); //erase from NPV as done with it there
11203  }
11204  }
11205  }
11206  Utilities->CallLogPop(2218);
11207  return(NumPlats);
11208 }
11209 
11210 // ---------------------------------------------------------------------------
11211 // UserGraphic, PrefDir & Route functions
11212 // ---------------------------------------------------------------------------
11213 
11215 {
11216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11217  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11218  {
11219  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11220  }
11221  Utilities->CallLogPop(2194);
11222  return(UserGraphicVector.at(At));
11223 }
11224 
11225 // ---------------------------------------------------------------------------
11226 
11227 int TOnePrefDir::LastElementNumber(int Caller) const
11228 {
11229  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11230  int RetVal = PrefDirVector.size() - 1;
11231 
11232  if(RetVal < 0)
11233  {
11234  throw Exception("Return value negative in call to LastElementNumber");
11235  }
11236  Utilities->CallLogPop(114);
11237  return(RetVal);
11238 }
11239 
11240 // ---------------------------------------------------------------------------
11242 {
11243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11244  if(PrefDirVector.empty())
11245  {
11246  throw Exception("PrefDirVector empty in call to LastElementPtr");
11247  }
11248  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11249 
11250  Utilities->CallLogPop(115);
11251  return(RetIT);
11252 }
11253 
11254 // ---------------------------------------------------------------------------
11256 {
11257  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11258  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11259  {
11260  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11261  }
11262  Utilities->CallLogPop(116);
11263  return(PrefDirVector.at(At));
11264 }
11265 
11266 // ---------------------------------------------------------------------------
11268 {
11269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11270  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11271  {
11272  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11273  " in GetModifiablePrefDirElementAt");
11274  }
11275  Utilities->CallLogPop(117);
11276  return(PrefDirVector.at(At));
11277 }
11278 
11279 // ---------------------------------------------------------------------------
11281 {
11282  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11283  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11284  {
11285  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11286  }
11287  Utilities->CallLogPop(118);
11288  return(SearchVector.at(At));
11289 }
11290 
11291 // ---------------------------------------------------------------------------
11293 {
11294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11295  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11296  {
11297  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11298  }
11299  Utilities->CallLogPop(119);
11300  return(SearchVector.at(At));
11301 }
11302 
11303 // ---------------------------------------------------------------------------
11304 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11305 /*
11306  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11307  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11308  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11309  set in later functions.
11310 */
11311 {
11312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11313  ClearPrefDir();
11314  int TrackVectorPosition;
11315  TTrackElement TrackElement;
11316 
11317  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11318  {
11319  Utilities->CallLogPop(126);
11320  return(false);
11321  }
11322 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11323  if(TrackElement.TrackType == Points)
11324  {
11325  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11326  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11327  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11328  //best to prevent it to avoid problems
11329  Utilities->CallLogPop(127);
11330  return false;
11331  }
11332 */
11333  TPrefDirElement PrefDirElement(TrackElement);
11334 
11335  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11336  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11337  StorePrefDirElement(1, PrefDirElement); // enter first element
11338 // Note that ELink not set even if a buffer or continuation - these set in
11339 // ConvertPrefDirSearchVector after 2nd element added
11340 
11341  Utilities->CallLogPop(128);
11342  return(true);
11343 }
11344 
11345 // ---------------------------------------------------------------------------
11346 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11347 
11348 /*
11349  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11350  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11351  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11352  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11353  so that the calling function knows that the PrefDir is complete.
11354  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11355  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11356  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11357  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11358  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11359  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11360  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11361  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11362 */
11363 
11364 {
11365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11366  FinishElement = false;
11367  int TrackVectorPosition;
11368 
11369  TotalSearchCount = 0;
11370  TTrackElement TrackElement, TempTrackElement;
11371 
11372  if(PrefDirVector.size() == 0)
11373  {
11374  Utilities->CallLogPop(129);
11375  return(false);
11376  }
11377  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11378  {
11379  Utilities->CallLogPop(130);
11380  return(false);
11381  }
11382 // set the search limits using the last stored element in PrefDirVector as the start point
11383 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11384 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11385 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11386 
11387  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11388 
11389  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11390  {
11391  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11392  SearchLimitHighH = TrackElement.HLoc + 15;
11393  }
11394  else
11395  {
11396  SearchLimitLowH = TrackElement.HLoc - 15;
11397  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11398  }
11399  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11400  {
11401  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11402  SearchLimitHighV = TrackElement.VLoc + 15;
11403  }
11404  else
11405  {
11406  SearchLimitLowV = TrackElement.VLoc - 15;
11407  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11408  }
11409 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11410  check & TotalSearchCounts check
11411  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11412  {
11413  ShowMessage("Unable to reach the selected element - too far ahead");
11414  Utilities->CallLogPop(1692);
11415  return false;
11416  }
11417 */
11418 // get last PrefDir element
11419  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11420  {
11421  // check if TrackElement adjacent to any of the 4 XLinkPos'
11422  for(int x = 0; x < 4; x++)
11423  {
11424  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11425  {
11426  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11427  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11428  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11429  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11430  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11431  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11432  // shouldn't ever get it in a serious railway though.
11433 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11434  }
11435  }
11436  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11437  {
11438  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11439  SearchVector.clear(); // use this & convert to set all PrefDir element values
11440  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11441  {
11443  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11444  {
11445  FinishElement = true;
11446  }
11447  Utilities->CallLogPop(131);
11448  return(true);
11449  }
11450  } // not an adjacent element
11451 
11452  // now check each of the 4 possible XLinkPos values
11453  for(int x = 0; x < 4; x++)
11454  {
11455  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11456  {
11457  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11458  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11459  SearchVector.clear();
11460  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11461  {
11463  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11464  {
11465  FinishElement = true;
11466  }
11467  Utilities->CallLogPop(132);
11468  return(true);
11469  }
11470  }
11471  } // here if checked all possible exits without success
11472  ShowMessage(
11473  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11474  Utilities->CallLogPop(133);
11475  return(false);
11476  }
11477 // dealt above with LastPrefDirElement being the start element (which can be points)
11478 
11479  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11480  .ELinkPos] == Lead)) // leading point
11481  {
11482  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11483  {
11484  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11485  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11486  // can't be buffers or gap if points
11487  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11488  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11489  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11490  SearchVector.clear();
11491  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11492  {
11494  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11495  {
11496  FinishElement = true;
11497  }
11498  Utilities->CallLogPop(134);
11499  return(true);
11500  }
11501  }
11502  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11503  {
11504  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11505  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11506  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11507  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11508  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11509  SearchVector.clear();
11510  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11511  {
11513  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11514  {
11515  FinishElement = true;
11516  }
11517  Utilities->CallLogPop(135);
11518  return(true);
11519  }
11520  }
11521 // above dealt with immediate finds for leading point,
11522 // now deal with ordinary searches for leading point
11523  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11524  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11525  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11526  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11527  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11528  SearchVector.clear();
11529  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11530  {
11532  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11533  {
11534  FinishElement = true;
11535  }
11536  Utilities->CallLogPop(136);
11537  return(true);
11538  }
11539  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11540  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11541  // note that CheckCount already increased to allow for XLinkPos & XLink
11542  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11543  SearchVector.clear();
11544  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11545  {
11547  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11548  {
11549  FinishElement = true;
11550  }
11551  Utilities->CallLogPop(137);
11552  return(true);
11553  }
11554 // here if failed to find match for leading point
11555  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11556  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11557  ShowMessage(
11558  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11559  Utilities->CallLogPop(138);
11560  return(false);
11561  }
11562 // leading point fully dealt with above
11563 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11564 // separately as covered in ordinary search.
11565 
11566  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11567  SearchVector.clear();
11568 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11569  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11570  {
11572  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11573  {
11574  FinishElement = true;
11575  }
11576  Utilities->CallLogPop(139);
11577  return(true);
11578  }
11579  ShowMessage(
11580  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11581  Utilities->CallLogPop(140);
11582  return(false); // failed to find required element
11583 }
11584 
11585 // ---------------------------------------------------------------------------
11586 
11587 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11588 /*
11589  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11590  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11591  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11592  Keep a count of entries in SearchVector during the current function call, so that this number can be
11593  erased for an unproductive branch search.
11594  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11595  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11596  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11597  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11598  If not any of above, store element in searchvector, set the new current element values from the
11599  SearchElement, then go back to the while loop for the next step in the search.
11600 */
11601 {
11602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11603  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11604  int VectorCount = 0;
11605 
11606  while(true)
11607  {
11608  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11609  {
11610  for(int x = 0; x < VectorCount; x++)
11611  {
11612  SearchVector.erase(SearchVector.end() - 1);
11613  }
11614  Utilities->CallLogPop(141);
11615  return(false);
11616  }
11617  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11618  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11619  TPrefDirElement SearchElement(NextTrackElement);
11620  SearchElement.TrackVectorPosition = NextPosition;
11621  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11622  SearchElement.ELinkPos = NextELinkPos;
11623  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11624  int NextXLinkPos;
11625  if(SearchElement.ELinkPos == 0)
11626  {
11627  NextXLinkPos = 1;
11628  }
11629  if(SearchElement.ELinkPos == 1)
11630  {
11631  NextXLinkPos = 0;
11632  }
11633  if(SearchElement.ELinkPos == 2)
11634  {
11635  NextXLinkPos = 3;
11636  }
11637  if(SearchElement.ELinkPos == 3)
11638  {
11639  NextXLinkPos = 2;
11640  }
11641  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11642  {
11643  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11644  // but may be buffers, continuation or gap
11645  SearchElement.XLinkPos = NextXLinkPos;
11646  }
11647 // can't set XLink or XLinkPos yet if the element is a leading point.
11648 // check if found it
11649  if(SearchElement.TrackVectorPosition == RequiredPosition)
11650  {
11651  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11652  VectorCount++; // not really needed but include for tidyness
11653  TotalSearchCount++;
11654  Utilities->CallLogPop(142);
11655  return(true);
11656  }
11657 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11658 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11659 // at a time - drop this
11660 /*
11661  if(PrefDirVector.size() > 200)
11662  {
11663  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11664  Utilities->CallLogPop(1419);
11665  return false;
11666  }
11667 */
11668 // check if a buffer or continuation
11669  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11670  {
11671  for(int x = 0; x < VectorCount; x++)
11672  {
11673  SearchVector.erase(SearchVector.end() - 1);
11674  }
11675  Utilities->CallLogPop(143);
11676  return(false);
11677  }
11678 // check if reached an earlier position on search PrefDir with same entry value
11679  for(unsigned int x = 0; x < SearchVector.size(); x++)
11680  {
11681  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11682  {
11683  for(int x = 0; x < VectorCount; x++)
11684  {
11685  SearchVector.erase(SearchVector.end() - 1);
11686  }
11687  Utilities->CallLogPop(144);
11688  return(false);
11689  }
11690  }
11691 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11692 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11693  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11694  {
11695  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11696  {
11697  for(int x = 0; x < VectorCount; x++)
11698  {
11699  SearchVector.erase(SearchVector.end() - 1);
11700  }
11701  Utilities->CallLogPop(1417);
11702  return(false);
11703  }
11704  }
11705 
11706 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11707 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11708 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11710  {
11711  for(int x = 0; x < VectorCount; x++)
11712  {
11713  SearchVector.erase(SearchVector.end() - 1);
11714  }
11715  Utilities->CallLogPop(1691);
11716  return(false);
11717  }
11718 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11719  if(SearchVector.size() > 150)
11720  {
11721  for(int x = 0; x < VectorCount; x++)
11722  {
11723  SearchVector.erase(SearchVector.end() - 1);
11724  }
11725  Utilities->CallLogPop(1418);
11726  return(false);
11727  }
11728 // check if reached a leading point
11729  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11730  {
11731 // push element with XLink set to position [1]
11732  SearchElement.XLink = SearchElement.Link[1];
11733  SearchElement.XLinkPos = 1;
11734  SearchVector.push_back(SearchElement);
11735  VectorCount++;
11736  TotalSearchCount++;
11737  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11738  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11739  // can't be used. NextTrackElement is the corresponding TTrackElement.
11740  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11741  {
11742  Utilities->CallLogPop(145);
11743  return(true);
11744  }
11745  else
11746  {
11747 // remove leading point with XLinkPos [1]
11748  SearchVector.erase(SearchVector.end() - 1);
11749  VectorCount--;
11750 // push element with XLink set to position [3]
11751  SearchElement.XLink = SearchElement.Link[3];
11752  SearchElement.XLinkPos = 3;
11753  SearchVector.push_back(SearchElement);
11754  VectorCount++;
11755  TotalSearchCount++;
11756 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11757  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11758  {
11759  Utilities->CallLogPop(146);
11760  return(true);
11761  }
11762  else
11763  {
11764  for(int x = 0; x < VectorCount; x++)
11765  {
11766  SearchVector.erase(SearchVector.end() - 1);
11767  }
11768  Utilities->CallLogPop(147);
11769  return(false);
11770  }
11771  }
11772  } // if leading point
11773 
11774 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11775 // ready for next element on PrefDir
11776  SearchVector.push_back(SearchElement);
11777  VectorCount++;
11778  TotalSearchCount++;
11779  XLinkPos = NextXLinkPos;
11780  CurrentTrackElement = SearchElement;
11781  } // while(true)
11782 }
11783 
11784 // ---------------------------------------------------------------------------
11785 
11787 /*
11788  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11789  for each element on the search PrefDir, though if the last element is a leading point
11790  then the final XLink won't be set.
11791  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11792  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11793  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11794 */
11795 {
11796  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11797  if(SearchVector.size() == 0)
11798  {
11799  throw Exception("Error, SearchVector empty");
11800  }
11801 // get first SearchElement in order to set last PrefDirelement
11802  TPrefDirElement SearchElement = SearchVector.at(0);
11803 
11804 // set last PrefDir element XLink & ELink values if not already set
11805 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11806  for(int x = 0; x < 4; x++)
11807  {
11808  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11809  {
11810  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11811  {
11812  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11813  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11814  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11815  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11816  }
11817  int ELinkPos;
11818  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11819  {
11820  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11821  }
11822  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
11823  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
11824  {
11825  ELinkPos = 0;
11826  }
11827  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
11828  {
11829  ELinkPos = 3;
11830  }
11831  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
11832  {
11833  ELinkPos = 2;
11834  }
11835  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
11836  {
11837  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
11838  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
11839  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
11840  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
11841  }
11842  break; // no point going any further
11843  }
11844  }
11845 // set EXNumber for last PrefDir element, unless already set
11846 // won't be set if was first element or a leading point
11847  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
11848  {
11849 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
11850  int EXArray[32][2] = {
11851  {4,6},{2,8}, //horizontal & vertical
11852  {2,4},{6,2},{8,6},{4,8}, //sharp curves
11853  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
11854  {1,9},{3,7} //forward & reverse diagonals
11855 */
11856 
11857  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
11858  {
11859  throw Exception("Error in EntryExitNumber 1");
11860  }
11861  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
11862  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
11863  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
11864  }
11865 // Last PrefDir element now complete
11866 
11867 // construct remaining PrefDir elements from searchvector
11868  for(unsigned int x = 0; x < SearchVector.size(); x++)
11869  {
11870  SearchElement = SearchVector.at(x);
11871  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
11872  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
11873  PrefDirElement.ELink = SearchElement.ELink;
11874  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
11875  PrefDirElement.XLink = SearchElement.XLink;
11876  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
11877 // if XLink & XLinkPos not set don't account for them in CheckCount
11878  if(PrefDirElement.XLink == -1)
11879  {
11880  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11881  }
11882  // & TrackVectorPosition
11883  else
11884  {
11885  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11886  }
11887  // XLink, XLinkPos, TrackVectorPosition
11888 
11889 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
11890  if(PrefDirElement.XLink != -1)
11891  {
11892  if(!(PrefDirElement.EntryExitNumber()))
11893  {
11894  throw Exception("Error in EntryExitNumber 2");
11895  }
11896  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11897  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11898  PrefDirElement.CheckCount++;
11899  // all values now incorporated if not a leading point
11900  }
11901 // store PrefDir element
11902  StorePrefDirElement(2, PrefDirElement);
11903  }
11904 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11905  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11906  {
11907  if(ValidatePrefDir(2))
11908  {
11909  ;
11910  } // error messages given within function
11911 
11912  }
11914 /* drop this, check dropped from search
11915  if(PrefDirVector.size() > 200)
11916  {
11917  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11918  }
11919 */
11920  Utilities->CallLogPop(148);
11921 }
11922 
11923 // ---------------------------------------------------------------------------
11924 
11925 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
11926 /*
11927  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
11928  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
11929 */
11930 {
11931  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
11932  LeadingPoints = false;
11933  if(PrefDirVector.empty())
11934  {
11935  Utilities->CallLogPop(1786);
11936  return(false); // should never be empty but allow for it for safety
11937  }
11938  if(PrefDirVector.size() == 1)
11939  {
11940  Utilities->CallLogPop(149);
11941  return(false); // can't end if only one element
11942  }
11943 /*
11944  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
11945  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
11946  {
11947  Utilities->CallLogPop(150);
11948  return true;
11949  }
11950 */
11951 // allow for anything but leading points
11952  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
11953  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
11954  {
11955  Utilities->CallLogPop(1776);
11956  return(true);
11957  }
11958  else
11959  {
11960  LeadingPoints = true;
11961  Utilities->CallLogPop(151);
11962  return(false);
11963  }
11964 }
11965 
11966 // ---------------------------------------------------------------------------
11967 
11969 /*
11970  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
11971  and that every element is connected to the next element
11972 */
11973 {
11974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
11975  int Position;
11976  AnsiString ErrorString;
11977  bool Error = false;
11978 
11979  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11980  {
11981  if(PrefDirVector.at(x).HLoc == -2000000000)
11982  {
11983  Error = true;
11984  ErrorString = "HLoc";
11985  Position = x;
11986  }
11987  if(PrefDirVector.at(x).VLoc == -2000000000)
11988  {
11989  Error = true;
11990  ErrorString = "VLoc";
11991  Position = x;
11992  }
11993  if(PrefDirVector.at(x).ELink == -1)
11994  {
11995  Error = true;
11996  ErrorString = "ELink";
11997  Position = x;
11998  }
11999  if(PrefDirVector.at(x).ELinkPos == -1)
12000  {
12001  Error = true;
12002  ErrorString = "ELinkPos";
12003  Position = x;
12004  }
12005  if(PrefDirVector.at(x).XLink == -1)
12006  {
12007  Error = true;
12008  ErrorString = "XLink";
12009  Position = x;
12010  }
12011  if(PrefDirVector.at(x).XLinkPos == -1)
12012  {
12013  Error = true;
12014  ErrorString = "XLinkPos";
12015  Position = x;
12016  }
12017  if(PrefDirVector.at(x).SpeedTag == 0)
12018  {
12019  Error = true;
12020  ErrorString = "Tag";
12021  Position = x;
12022  }
12023  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12024  {
12025  Error = true;
12026  ErrorString = "TrackVectorPosition";
12027  Position = x;
12028  }
12029  if(PrefDirVector.at(x).EXNumber == -1)
12030  {
12031  Error = true;
12032  ErrorString = "EXNumber";
12033  Position = x;
12034  }
12035  if(PrefDirVector.at(x).CheckCount != 9)
12036  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12037  {
12038  Error = true;
12039  ErrorString = "CheckCount";
12040  Position = x;
12041  }
12042 // extra checks
12043  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12044  {
12045  Error = true;
12046  ErrorString = "EntryGraphicPtr";
12047  Position = x;
12048  }
12049  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12050  {
12051  Error = true;
12052  ErrorString = "EntryDirectionGraphicPtr";
12053  Position = x;
12054  }
12055 // end of extra checks
12056  if(x > 0)
12057  {
12058  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12059  {
12060  Error = true;
12061  ErrorString = "Last XLink not connected to this element";
12062  Position = x;
12063  }
12064  }
12065  }
12066  if(Error)
12067  {
12068  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12069  }
12070  else
12071  {
12072  Utilities->CallLogPop(153);
12073  return(true);
12074  }
12075 }
12076 
12077 // ---------------------------------------------------------------------------
12078 
12079 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12080 /*
12081  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12082  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12083  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12084  or a leading point.
12085 */
12086 {
12087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12088  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12089  {
12090  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12091  {
12092  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12093  {
12094  ErasePrefDirElementAt(1, PrefDirVecPos);
12095  }
12096  if(PrefDirVector.size() == 0)
12097  {
12098  Utilities->CallLogPop(154);
12099  return(true);
12100  }
12101  if(PrefDirVector.size() == 1)
12102  {
12103  PrefDirVector.at(x - 1).ELinkPos = -1;
12104  PrefDirVector.at(x - 1).ELink = -1;
12105  PrefDirVector.at(x - 1).XLinkPos = -1;
12106  PrefDirVector.at(x - 1).XLink = -1;
12107  PrefDirVector.at(x - 1).EXNumber = -1;
12108  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12109  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12110  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12111  Utilities->CallLogPop(155);
12112  return(true);
12113  }
12114  // here with truncate element not first element, so ELink & ELinkPos set
12115  // unset XLink & Pos if a leading point
12116  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12117  {
12118  PrefDirVector.at(x - 1).XLinkPos = -1;
12119  PrefDirVector.at(x - 1).XLink = -1;
12120  PrefDirVector.at(x - 1).EXNumber = -1;
12121  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12122  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12123  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12124  Utilities->CallLogPop(156);
12125  return(true);
12126  }
12127  Utilities->CallLogPop(157);
12128  return(true);
12129  }
12130  }
12131  Utilities->CallLogPop(158);
12132  return(false);
12133 }
12134 
12135 // ---------------------------------------------------------------------------
12136 
12137 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12138 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12139 /*
12140  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12141  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12142  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12143  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12144  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12145  displayed.
12146 */
12147 {
12148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12149  AnsiString((short)BuildingPrefDir));
12150  int HPos, VPos;
12151 
12152  if(PrefDirSize() == 0)
12153  {
12154  Utilities->CallLogPop(159);
12155  return;
12156  }
12157  for(unsigned int x = 0; x < PrefDirSize(); x++)
12158  {
12159  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12160 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12161 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12162 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12163  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12164  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12165  // only the front half of which will be overplotted by the back of the train, then when the train is
12166  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12167  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12168  {
12169  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12170  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12171  {
12172  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12173  }
12174  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12175  // Route, no direction if a single element
12176  {
12177  if(x == 0)
12178  {
12179  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12180  }
12181  if(x == (PrefDirSize() - 1))
12182  {
12183  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12184  }
12185  }
12186  }
12187  }
12188 
12189 // set start & end element colours if building a PrefDir
12190  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12191  {
12192  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12193  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12194  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12195  // set last element colour
12196  if(PrefDirSize() > 1)
12197  {
12198  unsigned int LatestPos = PrefDirSize() - 1;
12199  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12200  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12201  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12202  }
12203  }
12204  Disp->Update();
12205  Utilities->CallLogPop(160);
12206 }
12207 
12208 // ---------------------------------------------------------------------------
12209 
12211 /*
12212  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12213  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12214 */
12215 {
12216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12217  if(PrefDirSize() == 0)
12218  {
12219  Utilities->CallLogPop(1547);
12220  return;
12221  }
12222  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12223  bool FoundFlag;
12225  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12226 
12227  while(MMIT != PrefDir4MultiMap.end())
12228  {
12229  H = MMIT->first.first;
12230  V = MMIT->first.second;
12231  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12232  // always found in order, any missing have PrefDirPosx == -1
12233  if(PrefDirPos0 > -1)
12234  {
12235  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12236  }
12237  if(PrefDirPos1 > -1)
12238  {
12239  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12240  }
12241  if(PrefDirPos2 > -1)
12242  {
12243  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12244  }
12245  if(PrefDirPos3 > -1)
12246  {
12247  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12248  }
12249  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12250  {
12251  // need to plot all 4 in order to obtain all the direction graphics
12252  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12253  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12254  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12255  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12256  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12257  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12258  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12259  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12260  MMIT++;
12261  MMIT++;
12262  MMIT++;
12263  MMIT++;
12264  }
12265  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12266  {
12267  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12268  {
12269  // 0 & 1 constitute the bidirectional PrefDir
12270  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12271  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12272  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12273  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12274  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12275  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12276  MMIT++;
12277  MMIT++;
12278  MMIT++;
12279  }
12280  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12281  {
12282  // 0 & 2 constitute the bidirectional PrefDir
12283  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12284  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12285  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12286  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12287  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12288  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12289  MMIT++;
12290  MMIT++;
12291  MMIT++;
12292  }
12293  else
12294  {
12295  // 1 & 2 constitute the bidirectional PrefDir
12296  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12297  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12298  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12299  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12300  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12301  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12302  MMIT++;
12303  MMIT++;
12304  MMIT++;
12305  }
12306  }
12307  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12308  {
12309  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12310  {
12311  // 0 & 1 constitute the bidirectional PrefDir
12312  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12313  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12314  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12315  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12316  MMIT++;
12317  MMIT++;
12318  }
12319  else
12320  {
12321  // 2 unidirectional PrefDirs
12322  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12323  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12324  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12325  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12326  MMIT++;
12327  MMIT++;
12328  }
12329  }
12330  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12331  {
12332  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12333  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12334  MMIT++;
12335  }
12336  }
12337  Disp->Update();
12338  Utilities->CallLogPop(1548);
12339 }
12340 
12341 // ---------------------------------------------------------------------------
12342 
12343 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12344 {
12345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12346  int TempInt;
12347 
12348  ClearPrefDir();
12349  int NumberOfPrefDirElements = 0;
12350 
12351  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12352  for(int x = 0; x < NumberOfPrefDirElements; x++)
12353  {
12354  VecFile >> TempInt; // TrackVectorPosition
12355  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12356  LoadPrefDirElement.TrackVectorPosition = TempInt;
12357  VecFile >> TempInt;
12358  LoadPrefDirElement.ELink = TempInt;
12359  VecFile >> TempInt;
12360  LoadPrefDirElement.ELinkPos = TempInt;
12361  VecFile >> TempInt;
12362  LoadPrefDirElement.XLink = TempInt;
12363  VecFile >> TempInt;
12364  LoadPrefDirElement.XLinkPos = TempInt;
12365  VecFile >> TempInt;
12366  LoadPrefDirElement.EXNumber = TempInt;
12367  VecFile >> TempInt;
12368  LoadPrefDirElement.CheckCount = TempInt;
12369  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12370  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12371  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12372  if(!(LoadPrefDirElement.IsARoute))
12373  {
12374  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12375  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12376  }
12377  else
12378  {
12379  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12380  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12381  LoadPrefDirElement.PrefDirRoute);
12382  }
12383  StorePrefDirElement(5, LoadPrefDirElement);
12384  Utilities->LoadFileString(VecFile); // marker
12385  }
12387  Utilities->CallLogPop(161);
12388 }
12389 
12390 // ---------------------------------------------------------------------------
12391 
12392 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12393 {
12394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12395  int TempInt;
12396 
12397  ClearPrefDir();
12398  int NumberOfPrefDirElements = 0;
12399 
12400  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12401  for(int x = 0; x < NumberOfPrefDirElements; x++)
12402  {
12403  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12404  VecFile >> TempInt; // TrackVectorPosition
12405  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12406  LoadPrefDirElement.TrackVectorPosition = TempInt;
12407  VecFile >> TempInt;
12408  LoadPrefDirElement.ELink = TempInt;
12409  VecFile >> TempInt;
12410  LoadPrefDirElement.ELinkPos = TempInt;
12411  VecFile >> TempInt;
12412  LoadPrefDirElement.XLink = TempInt;
12413  VecFile >> TempInt;
12414  LoadPrefDirElement.XLinkPos = TempInt;
12415  VecFile >> TempInt;
12416  LoadPrefDirElement.EXNumber = TempInt;
12417  VecFile >> TempInt;
12418  LoadPrefDirElement.CheckCount = TempInt;
12419  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12420  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12421  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12422  if(!(LoadPrefDirElement.IsARoute))
12423  {
12424  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12425  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12426  }
12427  else
12428  {
12429  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12430  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12431  LoadPrefDirElement.PrefDirRoute);
12432  }
12433  StorePrefDirElement(0, LoadPrefDirElement);
12434  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12435  }
12437  Utilities->CallLogPop(1509);
12438 }
12439 
12440 // ---------------------------------------------------------------------------
12441 
12442 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12443 /*
12444  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12445  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12446 */
12447 {
12448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12449  int TempInt;
12450  int NumberOfPrefDirElements = 0;
12451 
12452  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12453  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12454  {
12455  Utilities->CallLogPop(1152);
12456  return(false);
12457  }
12458  for(int x = 0; x < NumberOfPrefDirElements; x++)
12459  {
12460  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12461  {
12462  Utilities->CallLogPop(1766);
12463  return(false);
12464  }
12465  VecFile >> TempInt;
12466  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12467  {
12468  Utilities->CallLogPop(163);
12469  return(false);
12470  }
12471  VecFile >> TempInt;
12472  if((TempInt < -1) || (TempInt > 9)) // ELink
12473  {
12474  Utilities->CallLogPop(162);
12475  return(false);
12476  }
12477  VecFile >> TempInt;
12478  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12479  {
12480  Utilities->CallLogPop(164);
12481  return(false);
12482  }
12483  VecFile >> TempInt;
12484  if((TempInt < -1) || (TempInt > 9)) // XLink
12485  {
12486  Utilities->CallLogPop(165);
12487  return(false);
12488  }
12489  VecFile >> TempInt;
12490  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12491  {
12492  Utilities->CallLogPop(166);
12493  return(false);
12494  }
12495  VecFile >> TempInt;
12496  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12497  {
12498  Utilities->CallLogPop(167);
12499  return(false);
12500  }
12501  VecFile >> TempInt;
12502  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12503  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12504  // ELinkPos, XLink, XLinkPos & EXNumber
12505  {
12506  Utilities->CallLogPop(168);
12507  return(false);
12508  }
12509  VecFile >> TempInt;
12510  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12511  {
12512  Utilities->CallLogPop(1147);
12513  return(false);
12514  }
12515  VecFile >> TempInt;
12516  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12517  {
12518  Utilities->CallLogPop(1510);
12519  return(false);
12520  }
12521  VecFile >> TempInt;
12522  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12523  {
12524  Utilities->CallLogPop(1148);
12525  return(false);
12526  }
12527  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12528  {
12529  Utilities->CallLogPop(1700);
12530  return(false);
12531  }
12532  }
12533  Utilities->CallLogPop(169);
12534  return(true);
12535 }
12536 
12537 // ---------------------------------------------------------------------------
12538 
12539 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12540 {
12541  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12542  int NumberOfPrefDirElements = PrefDirVector.size();
12543 
12544  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12545  for(int y = 0; y < NumberOfPrefDirElements; y++)
12546  {
12547  VecFile << y << '\n'; // extra
12548  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12549  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12550  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12551  VecFile << PrefDirVector.at(y).XLink << '\n';
12552  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12553  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12554  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12555  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12556  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12557  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12558  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12559  {
12560  VecFile << "************" << '\0' << '\n'; // marker
12561  }
12562  else
12563  {
12564  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12565  }
12566  }
12567  Utilities->CallLogPop(170);
12568 }
12569 
12570 // ---------------------------------------------------------------------------
12571 
12572 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12573 {
12574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12575  int NumberOfSearchElements = SearchVector.size();
12576 
12577  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12578  for(int y = 0; y < NumberOfSearchElements; y++)
12579  {
12580  VecFile << y << '\n'; // extra
12581  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12582  VecFile << SearchVector.at(y).ELink << '\n';
12583  VecFile << SearchVector.at(y).ELinkPos << '\n';
12584  VecFile << SearchVector.at(y).XLink << '\n';
12585  VecFile << SearchVector.at(y).XLinkPos << '\n';
12586  VecFile << SearchVector.at(y).EXNumber << '\n';
12587  VecFile << SearchVector.at(y).CheckCount << '\n';
12588  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12589  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12590  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12591  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12592  {
12593  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12594  }
12595  else
12596  {
12597  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12598  }
12599  }
12600  Utilities->CallLogPop(1847);
12601 }
12602 
12603 // ---------------------------------------------------------------------------
12604 
12605 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12606 /*
12607  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12608  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12609 */
12610 {
12611  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12612  AnsiString(VLoc));
12613  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12614 
12615  if(VecPos > -1)
12616  {
12617  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12618  }
12619  else
12620  {
12621  Utilities->CallLogPop(171);
12622  return;
12623  }
12624  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12625  if(VecPos > -1)
12626  {
12627  ErasePrefDirElementAt(3, VecPos);
12628  }
12629  else
12630  {
12631  Utilities->CallLogPop(172);
12632  return;
12633  }
12634  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12635  if(VecPos > -1)
12636  {
12637  ErasePrefDirElementAt(4, VecPos);
12638  }
12639  else
12640  {
12641  Utilities->CallLogPop(173);
12642  return;
12643  }
12644  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12645  if(VecPos > -1)
12646  {
12647  ErasePrefDirElementAt(5, VecPos);
12648  }
12649  else
12650  {
12651  Utilities->CallLogPop(174);
12652  return;
12653  }
12654  Utilities->CallLogPop(175);
12655 }
12656 
12657 // ---------------------------------------------------------------------------
12658 /*
12659  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12660  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12661 
12662  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12663  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12664  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12665  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12666  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12667  PrefDirVector to correspond to the new track layout.
12668 
12669  {
12670  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12671  if(PrefDirSize() == 0)
12672  {
12673  Utilities->CallLogPop(176);
12674  return;
12675  }
12676  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12677  {
12678  int TV = PrefDirVector.at(x).TrackVectorPosition;
12679  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12680  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12681  if(Track->BlankElementAt(0, TV))
12682  {
12683  ErasePrefDirElementAt(6, x);
12684  }
12685  //if was a blankelement at x then ConnELink and ConnXLink both -1
12686  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12687  {
12688  ErasePrefDirElementAt(7, x);
12689  }
12690  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12691  //needs to be erased once, but if don't use 'else' then will erase two elements
12692  //since 'x' will correspond to the element after the first erased element
12693  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12694  {
12695  ErasePrefDirElementAt(8, x);
12696  }
12697  }
12698  Utilities->CallLogPop(177);
12699  }
12700 */
12701 // ---------------------------------------------------------------------------
12702 
12703 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12704 /*
12705  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12706  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12707 */
12708 {
12709  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12710  bool AlreadyPresent, FoundFlag;
12711  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12712 
12713  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12714  {
12715  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12716  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12717  AlreadyPresent = false;
12718  if(FoundFlag)
12719  {
12720  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12721  {
12722  AlreadyPresent = true;
12723  }
12724  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12725  {
12726  AlreadyPresent = true;
12727  }
12728  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12729  {
12730  AlreadyPresent = true;
12731  }
12732  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12733  {
12734  AlreadyPresent = true;
12735  }
12736  }
12737  if(!AlreadyPresent)
12738  {
12739  StorePrefDirElement(4, TempElement);
12740  }
12741  }
12743  Utilities->CallLogPop(178);
12744 }
12745 /* earlier brute force search
12746  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12747  {
12748  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12749  bool AlreadyPresent = false;
12750  for(unsigned int y = 0;y<PrefDirSize();y++)
12751  {
12752  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12753  }
12754  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12755  }
12756 */
12757 
12758 // ---------------------------------------------------------------------------
12759 
12761 /*
12762  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12763  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12764  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12765  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12766  positions are likely to have changed, so this function is called to reset all the necessary connections and
12767  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12768  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12769  shouldn't have changed.
12770 */
12771 {
12772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12773  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12774  {
12775  bool FoundFlag;
12776  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12777  if(FoundFlag)
12778  {
12779  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12780  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12781  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12782  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12783  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12784  for(unsigned int z = 0; z < 4; z++)
12785  {
12786  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12787  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12788  }
12789  }
12790  else
12791  {
12792  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12793  }
12794  }
12795  Utilities->CallLogPop(179);
12796 }
12797 
12798 // ---------------------------------------------------------------------------
12799 
12801 /*
12802  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12803 */
12804 {
12805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12806  bool DiscrepancyFound = false;
12807 
12808  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12809  {
12810  bool FoundFlag;
12811  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12812  if(FoundFlag)
12813  {
12814  TPrefDirElement PE = PrefDirVector.at(x);
12815  if(PE.TrackVectorPosition != VecPos)
12816  {
12817  DiscrepancyFound = true;
12818  break;
12819  }
12820  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12821  {
12822  DiscrepancyFound = true;
12823  break;
12824  }
12825  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12826  {
12827  DiscrepancyFound = true;
12828  break;
12829  }
12830  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
12831  {
12832  DiscrepancyFound = true;
12833  break;
12834  }
12835  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
12836  {
12837  DiscrepancyFound = true;
12838  break;
12839  }
12840  }
12841  else
12842  {
12843  DiscrepancyFound = true;
12844  }
12845  }
12846  if(DiscrepancyFound)
12847  {
12848  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
12849  ClearPrefDir(); // also clears multimap
12850  }
12851  Utilities->CallLogPop(1436);
12852 }
12853 
12854 // ---------------------------------------------------------------------------
12855 
12857 /*
12858  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
12859  return true for OK
12860 */
12861 {
12862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
12863  bool DiscrepancyFound = false;
12864 
12865  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12866  {
12867  bool FoundFlag;
12868  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12869  if(FoundFlag)
12870  {
12871  TPrefDirElement PE = PrefDirVector.at(x);
12872  if(PE.TrackVectorPosition != VecPos)
12873  {
12874  DiscrepancyFound = true;
12875  }
12876  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12877  {
12878  DiscrepancyFound = true;
12879  break;
12880  }
12881  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12882  {
12883  DiscrepancyFound = true;
12884  break;
12885  }
12886  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
12887  {
12888  DiscrepancyFound = true;
12889  break;
12890  }
12891  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
12892  {
12893  DiscrepancyFound = true;
12894  break;
12895  }
12896  }
12897  else
12898  {
12899  DiscrepancyFound = true;
12900  }
12901  }
12902  Utilities->CallLogPop(1512);
12903  return(!DiscrepancyFound);
12904 }
12905 
12906 // ---------------------------------------------------------------------------
12907 
12908 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
12909 /*
12910  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
12911  turn and for the overall sizes.
12912 */
12913 {
12914  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
12915  bool FoundFlag = false;
12916  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
12917 
12918  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
12919  {
12920  TPrefDirElement CheckElement = PrefDirVector.at(a);
12921  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
12922  if(!FoundFlag)
12923  {
12924  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
12925  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
12926  }
12927  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
12928  {
12929  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
12930  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
12931  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
12932  }
12933  }
12934  if(PrefDirVector.size() != PrefDir4MultiMap.size())
12935  {
12936  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
12937  + " Caller=" + (AnsiString)Caller);
12938  }
12939  Utilities->CallLogPop(180);
12940 }
12941 
12942 // ---------------------------------------------------------------------------
12943 
12944 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
12945  int &PrefDirPos3)
12946 /*
12947  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
12948  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
12949  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
12950  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
12951  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
12952 */
12953 {
12954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
12955  AnsiString(VLoc));
12956  THVPair PrefDirMapKeyPair;
12957 
12958  PrefDirPos0 = -1;
12959  PrefDirPos1 = -1;
12960  PrefDirPos2 = -1;
12961  PrefDirPos3 = -1;
12962  FoundFlag = false;
12963  PrefDirMapKeyPair.first = HLoc;
12964  PrefDirMapKeyPair.second = VLoc;
12965  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12966 
12967  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
12968  if(ItPair.first == ItPair.second) //none found
12969  {
12970  Utilities->CallLogPop(181);
12971  return;
12972  }
12973  else
12974  {
12975  FoundFlag = true;
12976  PrefDirPos0 = ItPair.first->second;
12977  ItPair.first++;
12978  if(ItPair.first == ItPair.second)
12979  {
12980  Utilities->CallLogPop(182); //only one found
12981  return;
12982  }
12983  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12984  {
12985  PrefDirPos1 = ItPair.first->second;
12986  }
12987  ItPair.first++;
12988  if(ItPair.first == ItPair.second)
12989  {
12990  Utilities->CallLogPop(183); //2 found
12991  return;
12992  }
12993  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12994  {
12995  PrefDirPos2 = ItPair.first->second;
12996  }
12997  ItPair.first++;
12998  if(ItPair.first == ItPair.second)
12999  {
13000  Utilities->CallLogPop(184); //3 found
13001  return;
13002  }
13003  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13004  {
13005  PrefDirPos3 = ItPair.first->second; //4 found
13006  }
13007  }
13008  Utilities->CallLogPop(185);
13009 }
13010 
13011 // ---------------------------------------------------------------------------
13012 
13013 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13014 {
13015  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13016  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13017  try
13018  {
13019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13020  + "," + AnsiString(LinkNumberPos));
13021  bool FoundFlag;
13022  int PD0, PD1, PD2, PD3;
13023  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13024  {
13025  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13026  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13027  PD0, PD1, PD2, PD3);
13028  if(!FoundFlag)
13029  {
13030  Utilities->CallLogPop(2282);
13031  return(false);
13032  }
13033  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13034  {
13035  if(PD0 > -1)
13036  {
13037  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13038  {
13039  LinkedPrefDirVectorNumber = PD0;
13040  Utilities->CallLogPop(2283);
13041  return(true);
13042  }
13043  }
13044  if(PD1 > -1)
13045  {
13046  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13047  {
13048  LinkedPrefDirVectorNumber = PD1;
13049  Utilities->CallLogPop(2284);
13050  return(true);
13051  }
13052  }
13053  }
13054  if(PD0 > -1)
13055  {
13056  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13057  {
13058  LinkedPrefDirVectorNumber = PD0;
13059  Utilities->CallLogPop(2285);
13060  return(true);
13061  }
13062  }
13063  if(PD1 > -1)
13064  {
13065  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13066  {
13067  LinkedPrefDirVectorNumber = PD1;
13068  Utilities->CallLogPop(2286);
13069  return(true);
13070  }
13071  }
13072  if(PD2 > -1)
13073  {
13074  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13075  {
13076  LinkedPrefDirVectorNumber = PD2;
13077  Utilities->CallLogPop(2287);
13078  return(true);
13079  }
13080  }
13081  if(PD3 > -1)
13082  {
13083  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13084  {
13085  LinkedPrefDirVectorNumber = PD3;
13086  Utilities->CallLogPop(2288);
13087  return(true);
13088  }
13089  }
13090  LinkedPrefDirVectorNumber = -1;
13091  Utilities->CallLogPop(2289);
13092  return(false);
13093  }
13094  else //buffer or continuation, no link at position 0 but not a failure
13095  {
13096  LinkedPrefDirVectorNumber = -1;
13097  Utilities->CallLogPop(2290);
13098  return(true);
13099  }
13100  }
13101  catch(const Exception &e) //non error catch
13102  {
13103  LinkedPrefDirVectorNumber = -1;
13104  Utilities->CallLogPop(2291);
13105  return(false);
13106  }
13107 }
13108 
13109 // ---------------------------------------------------------------------------
13110 
13112 {
13113  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13114  bool FoundFlag; //not used
13115  int PD0, PD1, PD2, PD3;
13116  //recover all PDs at the H & V of PDPtr
13117  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13118 
13119  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13120  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13121 
13122  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13123  {
13124  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13125  {
13126  Utilities->CallLogPop(2292);
13127  return(true);
13128  }
13129  }
13130  if(PD1 > -1)
13131  {
13132  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13133  {
13134  Utilities->CallLogPop(2293);
13135  return(true);
13136  }
13137  }
13138  if(PD2 > -1)
13139  {
13140  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13141  {
13142  Utilities->CallLogPop(2294);
13143  return(true);
13144  }
13145  }
13146  if(PD3 > -1)
13147  {
13148  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13149  {
13150  Utilities->CallLogPop(2295);
13151  return(true);
13152  }
13153  }
13154  Utilities->CallLogPop(2296);
13155  return(false);
13156 }
13157 
13158 // ---------------------------------------------------------------------------
13159 
13160 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13161 /*
13162  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13163 */
13164 {
13165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13166  PrefDirVector.push_back(LoadPrefDirElement);
13167  THVPair PrefDir4MultiMapKeyPair;
13168  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13169 
13170  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13171  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13172  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13173  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13174  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13175 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13176  Utilities->CallLogPop(186);
13177 }
13178 
13179 // ---------------------------------------------------------------------------
13180 
13181 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13182 /*
13183  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13184  4MultiMap if they are greater than the erased value.
13185 */
13186 {
13187  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13188  bool FoundFlag;
13189 
13190  if(!PrefDirVector.empty())
13191  {
13192  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13193  if(!FoundFlag)
13194  {
13195  throw Exception("Failed to find PrefDir4MultiMap erase element");
13196  }
13197  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13198  PrefDir4MultiMap.erase(EraseIt);
13199  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13201  }
13202  Utilities->CallLogPop(187);
13203 }
13204 
13205 // ---------------------------------------------------------------------------
13206 
13207 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13208 /*
13209  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13210  4MultiMap if they are greater than the erased value.
13211 */
13212 {
13213  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13214  AnsiString(ErasedElementNumber));
13215  if(!PrefDir4MultiMap.empty())
13216  {
13217  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13218  {
13219  if(MapPtr->second > ErasedElementNumber)
13220  {
13221  MapPtr->second--;
13222  }
13223  }
13224  }
13225  Utilities->CallLogPop(1450);
13226 }
13227 
13228 // ---------------------------------------------------------------------------
13229 
13230 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13231 /*
13232  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13233  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13234  nothing is found this is an error but the error message is given in the calling function.
13235 */
13236 {
13237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13238  FoundFlag = false;
13239  if(PrefDirVectorPosition >= PrefDirVector.size())
13240  {
13241  throw Exception("PrefDirVectorPosition out of range");
13242  }
13243  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13244  THVPair PrefDir4MultiMapKeyPair;
13245 
13246  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13247  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13248  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13249 
13250  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13251  if(ItPair.first == ItPair.second)
13252  {
13253  Utilities->CallLogPop(188);
13254  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13255  }
13256  else
13257  {
13258  if(ItPair.first->second == PrefDirVectorPosition)
13259  {
13260  FoundFlag = true;
13261  Utilities->CallLogPop(189);
13262  return(ItPair.first);
13263  }
13264  ItPair.first++;
13265  if(ItPair.first == ItPair.second)
13266  {
13267  Utilities->CallLogPop(190);
13268  return(ItPair.first); // nothing found
13269  }
13270  if(ItPair.first->second == PrefDirVectorPosition)
13271  {
13272  FoundFlag = true;
13273  Utilities->CallLogPop(191);
13274  return(ItPair.first);
13275  }
13276  ItPair.first++;
13277  if(ItPair.first == ItPair.second)
13278  {
13279  Utilities->CallLogPop(192);
13280  return(ItPair.first); // nothing found
13281  }
13282  if(ItPair.first->second == PrefDirVectorPosition)
13283  {
13284  FoundFlag = true;
13285  Utilities->CallLogPop(193);
13286  return(ItPair.first);
13287  }
13288  ItPair.first++;
13289  if(ItPair.first == ItPair.second)
13290  {
13291  Utilities->CallLogPop(194);
13292  return(ItPair.first); // nothing found
13293  }
13294  if(ItPair.first->second == PrefDirVectorPosition)
13295  {
13296  FoundFlag = true;
13297  Utilities->CallLogPop(195);
13298  return(ItPair.first);
13299  }
13300  }
13301  Utilities->CallLogPop(196);
13302  return(ItPair.first); // nothing found
13303 }
13304 
13305 // ---------------------------------------------------------------------------
13306 
13307 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13308 /*
13309  Although there may be up to four entries at one H & V position this function gets just one. It is
13310  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13311  at H & V.
13312 */
13313 {
13314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13315  THVPair PrefDir4MultiMapKeyPair;
13316 
13317  PrefDir4MultiMapKeyPair.first = HLoc;
13318  PrefDir4MultiMapKeyPair.second = VLoc;
13319  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13320 
13321  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13322  if(ItPair.first == ItPair.second) // nothing found
13323  {
13324  Utilities->CallLogPop(197);
13325  return(-1);
13326  }
13327  else
13328  {
13329  Utilities->CallLogPop(198);
13330  return(ItPair.first->second);
13331  }
13332 }
13333 
13334 // ---------------------------------------------------------------------------
13335 
13336 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13337 {
13338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13339  bool ErasedFlag = false;
13340 
13341  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13342  {
13343  if(PrefDirSize() == 0)
13344  {
13345  Utilities->CallLogPop(1511);
13346  return;
13347  }
13348  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13349  {
13350  ErasedFlag = false;
13351  // use 'else' to ensure don't try to access an erased element
13352  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13353  {
13354  ErasePrefDirElementAt(11, x);
13355  ErasedFlag = true;
13356  }
13357  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13358  {
13359  ErasePrefDirElementAt(12, x);
13360  ErasedFlag = true;
13361  }
13362  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13363  {
13364  ErasePrefDirElementAt(13, x);
13365  ErasedFlag = true;
13366  }
13367  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13368  {
13369  ErasePrefDirElementAt(9, x);
13370  ErasedFlag = true;
13371  }
13372  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13373  {
13374  ErasePrefDirElementAt(10, x);
13375  ErasedFlag = true;
13376  }
13377  if(!ErasedFlag)
13378  {
13379  // don't use 'else' here as may be more than one that need decrementing
13380  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13381  {
13382  PrefDirVector.at(x).TrackVectorPosition--;
13383  }
13384  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13385  {
13386  PrefDirVector.at(x).Conn[0]--;
13387  }
13388  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13389  {
13390  PrefDirVector.at(x).Conn[1]--;
13391  }
13392  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13393  {
13394  PrefDirVector.at(x).Conn[2]--;
13395  }
13396  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13397  {
13398  PrefDirVector.at(x).Conn[3]--;
13399  }
13400  }
13401  }
13402  }
13403  Utilities->CallLogPop(1434);
13404 }
13405 
13406 // ---------------------------------------------------------------------------
13407 
13408 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13409 {
13410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13411  OverallDistance = 0;
13412  OverallSpeedLimit = 0;
13413  LeadingPointsAtLastElement = false;
13414  if(PrefDirSize() == 0) // shouldn't be empty when this called
13415  {
13416  Utilities->CallLogPop(1491);
13417  return;
13418  }
13419  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13420  {
13421  LeadingPointsAtLastElement = true;
13422  Utilities->CallLogPop(1492);
13423  return;
13424  }
13425  for(unsigned int x = 0; x < PrefDirSize(); x++)
13426  {
13427  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13428  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13429  {
13430  OverallDistance += PrefDirElement.Length23;
13431  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13432  {
13433  if(x == 0)
13434  {
13435  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13436  }
13437  else
13438  {
13439  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13440  {
13441  OverallSpeedLimit = -1;
13442  }
13443  }
13444  }
13445  }
13446  else
13447  {
13448  OverallDistance += PrefDirElement.Length01;
13449  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13450  {
13451  if(x == 0)
13452  {
13453  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13454  }
13455  else
13456  {
13457  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13458  {
13459  OverallSpeedLimit = -1;
13460  }
13461  }
13462  }
13463  }
13464  }
13465  Utilities->CallLogPop(1529);
13466 }
13467 
13468 // ---------------------------------------------------------------------------
13469 
13470 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13471 {
13472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13473  if(PrefDirSize() == 0)
13474  {
13475  Utilities->CallLogPop(1564);
13476  return;
13477  }
13478  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13479  bool FoundFlag;
13481  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13482 
13483  while(MMIT != PrefDir4MultiMap.end())
13484  {
13485  HLoc = MMIT->first.first;
13486  VLoc = MMIT->first.second;
13487  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13488  H = HLoc - Track->GetHLocMin();
13489  V = VLoc - Track->GetVLocMin();
13490  // always found in order, any missing have PrefDirPosx == -1
13491  if(PrefDirPos0 > -1)
13492  {
13493  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13494  }
13495  if(PrefDirPos1 > -1)
13496  {
13497  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13498  }
13499  if(PrefDirPos2 > -1)
13500  {
13501  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13502  }
13503  if(PrefDirPos3 > -1)
13504  {
13505  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13506  }
13507  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13508  {
13509  // need to plot all 4 in order to obtain all the direction graphics
13510  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13511  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13512  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13513  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13514  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13515  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13516  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13517  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13518  MMIT++;
13519  MMIT++;
13520  MMIT++;
13521  MMIT++;
13522  }
13523  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13524  {
13525  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13526  {
13527  // 0 & 1 constitute the bidirectional PrefDir
13528  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13529  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13530  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13531  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13532  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13533  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13534  MMIT++;
13535  MMIT++;
13536  MMIT++;
13537  }
13538  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13539  {
13540  // 0 & 2 constitute the bidirectional PrefDir
13541  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13542  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13543  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13544  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13545  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13546  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13547  MMIT++;
13548  MMIT++;
13549  MMIT++;
13550  }
13551  else
13552  {
13553  // 1 & 2 constitute the bidirectional PrefDir
13554  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13555  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13556  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13557  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13558  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13559  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13560  MMIT++;
13561  MMIT++;
13562  MMIT++;
13563  }
13564  }
13565  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13566  {
13567  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13568  {
13569  // 0 & 1 constitute the bidirectional PrefDir
13570  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13571  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13572  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13573  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13574  MMIT++;
13575  MMIT++;
13576  }
13577  else
13578  {
13579  // 2 unidirectional PrefDirs
13580  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13581  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13582  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13583  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13584  MMIT++;
13585  MMIT++;
13586  }
13587  }
13588  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13589  {
13590  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13591  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13592  MMIT++;
13593  }
13594  }
13595  Utilities->CallLogPop(1565);
13596 }
13597 
13598 // ---------------------------------------------------------------------------
13599 
13600 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13601 /*
13602  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13603  level crossing, signals with wrong direction set, or buffers.
13604 */
13605 {
13606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13607  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13608  bool FoundFlag;
13610  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13611 
13612  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13613  ElementIn.VLoc)))
13614  {
13615  Utilities->CallLogPop(1982);
13616  return(false);
13617  }
13618  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13619  {
13620  Utilities->CallLogPop(1983);
13621  return(false);
13622  }
13623  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13624  {
13625  Utilities->CallLogPop(1995);
13626  return(false);
13627  }
13628 // Now check that there is only a single prefdir set
13629  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13630 // always found in order, any missing have PrefDirPosx == -1
13631  if(PrefDirPos0 > -1)
13632  {
13633  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13634  }
13635  if(PrefDirPos1 > -1)
13636  {
13637  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13638  }
13639  if(PrefDirPos2 > -1)
13640  {
13641  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13642  }
13643  if(PrefDirPos3 > -1)
13644  {
13645  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13646  }
13647  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13648  {
13649  Utilities->CallLogPop(1984);
13650  return(false);
13651  }
13652  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13653  {
13654  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13655  {
13656  Utilities->CallLogPop(1985);
13657  return(false);
13658  }
13659  else
13660  {
13661  Utilities->CallLogPop(1986);
13662  return(true);
13663  }
13664  }
13665  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13666  {
13667  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13668  {
13669  Utilities->CallLogPop(1987);
13670  return(false);
13671  }
13672  else
13673  {
13674  Utilities->CallLogPop(1988);
13675  return(true);
13676  }
13677  }
13678  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13679  {
13680  if(PrefDirElement0.XLinkPos == EntryPos)
13681  {
13682  Utilities->CallLogPop(1989);
13683  return(false);
13684  }
13685  else
13686  {
13687  Utilities->CallLogPop(1990);
13688  return(true);
13689  }
13690  }
13691  else
13692  {
13693  Utilities->CallLogPop(1991);
13694  return(false); // none found
13695  }
13696 }
13697 
13698 // ---------------------------------------------------------------------------
13699 
13701 {
13702 /* //Added at v2.1.0
13703  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13704  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13705  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13706  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13707  and can be modelled better anyway.
13708 
13709  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13710  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13711  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13712  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13713  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13714  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13715 */
13716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13717  ElementIn.VLoc + "," + XLink);
13718  int TrackVecPos;
13719  bool TrackFoundFlag;
13720  TTrackElement TempTrackElement;
13721 
13722  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13723  {
13724  Utilities->CallLogPop(2047);
13725  return(false);
13726  }
13727 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13728  if(XLink == 1)
13729  {
13730  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13731  if(TrackFoundFlag)
13732  {
13733  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13734  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13735  {
13736  Utilities->CallLogPop(2048);
13737  return(true);
13738  }
13739  }
13740  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13741  if(TrackFoundFlag)
13742  {
13743  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13744  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13745  {
13746  Utilities->CallLogPop(2049);
13747  return(true);
13748  }
13749  }
13750  }
13751 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13752  if(XLink == 3)
13753  {
13754  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13755  if(TrackFoundFlag)
13756  {
13757  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13758  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13759  {
13760  Utilities->CallLogPop(2050);
13761  return(true);
13762  }
13763  }
13764  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13765  if(TrackFoundFlag)
13766  {
13767  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13768  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13769  {
13770  Utilities->CallLogPop(2051);
13771  return(true);
13772  }
13773  }
13774  }
13775 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13776  if(XLink == 7)
13777  {
13778  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13779  if(TrackFoundFlag)
13780  {
13781  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13782  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13783  {
13784  Utilities->CallLogPop(2052);
13785  return(true);
13786  }
13787  }
13788  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13789  if(TrackFoundFlag)
13790  {
13791  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13792  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13793  {
13794  Utilities->CallLogPop(2053);
13795  return(true);
13796  }
13797  }
13798  }
13799 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13800  if(XLink == 9)
13801  {
13802  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13803  if(TrackFoundFlag)
13804  {
13805  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13806  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13807  {
13808  Utilities->CallLogPop(2054);
13809  return(true);
13810  }
13811  }
13812  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13813  if(TrackFoundFlag)
13814  {
13815  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13816  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13817  {
13818  Utilities->CallLogPop(2055);
13819  return(true);
13820  }
13821  }
13822  }
13823  Utilities->CallLogPop(2056);
13824  return(false);
13825 }
13826 
13827 // ---------------------------------------------------------------------------
13828 
13829 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
13830 {
13831 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
13832  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
13833  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
13834  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
13835  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
13836 */
13837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
13839  bool FoundFlag, ContFlag, FoundElements = false;
13840  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13841  TPrefDirElement NextElement;
13842 
13843  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
13844  {
13845  LastIteratorValue++;
13846  ContFlag = false;
13847  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
13848  {
13849  continue;
13850  }
13851  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
13852  {
13853  continue;
13854  }
13855 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
13856  // found a potential route start point
13857  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
13858  {
13859  continue;
13860  }
13861  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
13862  {
13863  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
13864  if(PDVIt->TrackType == Continuation)
13865  {
13866  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
13867  {
13868  continue;
13869  }
13870  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
13871  {
13872  continue;
13873  }
13874  }
13875  StartElement = *PDVIt;
13876 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
13877  // diverging track on which there was no pref dir. See below for 2 required changes.
13878  }
13879  else
13880  {
13881  continue;
13882  }
13883  // now track along until find a signal or continuation, checking validity for each element
13884  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
13885  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
13886  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13887  if(PrefDirPos0 == -1) // no continuing prefdir
13888  {
13889  continue;
13890  }
13891  bool NextElementFoundFlag = false;
13892  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13893  {
13894  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
13895  NextElementFoundFlag = true;
13896  }
13897  if(PrefDirPos1 > -1)
13898  {
13899  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13900  {
13901  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
13902  NextElementFoundFlag = true;
13903  }
13904  }
13905  if(PrefDirPos2 > -1)
13906  {
13907  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13908  {
13909  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
13910  NextElementFoundFlag = true;
13911  }
13912  }
13913  if(PrefDirPos3 > -1)
13914  {
13915  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13916  {
13917  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
13918  NextElementFoundFlag = true;
13919  }
13920  }
13921  if(!NextElementFoundFlag)
13922  {
13923  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
13924 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
13925  }
13926  while(true)
13927  {
13928  // check validity
13929  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
13930  {
13931  ContFlag = true;
13932  break;
13933  }
13934  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
13935  {
13936  ContFlag = true;
13937  break;
13938  }
13939  // check if in a route, providing not a signal, as a signal might be at the start of a route
13940  if(NextElement.TrackType != SignalPost)
13941  {
13942  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
13943  {
13944  ContFlag = true;
13945  break;
13946  }
13947  }
13948  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
13949  // can't be a gound signal as would have failed the validity test
13950  {
13951  EndElement = NextElement;
13952  break;
13953  }
13954  // get the next element in the sequence
13955  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
13956  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
13957  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13958  if(PrefDirPos0 == -1) // no continuing prefdir
13959  {
13960  ContFlag = true;
13961  break;
13962  }
13963  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13964  {
13965  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
13966  continue;
13967  }
13968  if(PrefDirPos1 > -1)
13969  {
13970  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13971  {
13972  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
13973  continue;
13974  }
13975  }
13976  if(PrefDirPos2 > -1)
13977  {
13978  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13979  {
13980  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
13981  continue;
13982  }
13983  }
13984  if(PrefDirPos3 > -1)
13985  {
13986  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13987  {
13988  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
13989  continue;
13990  }
13991  }
13992  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
13993  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
13994  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
13995  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
13996  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
13997  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
13998  {
13999  ContFlag = true;
14000  break;
14001  }
14002  else
14003  {
14004  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14005  // could drop the bridge test but keep it to show the change history
14006  break;
14007 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14008  }
14009  }
14010  if(ContFlag)
14011  {
14012  continue;
14013  }
14014  // else have start and end elements set & all elements valid, so set up the route segment
14015  FoundElements = true;
14016  break;
14017  }
14018  if(FoundElements)
14019  {
14020  Utilities->CallLogPop(1992);
14021  return(true);
14022  }
14023  else
14024  {
14025  Utilities->CallLogPop(1993);
14026  return(false);
14027  }
14028 }
14029 
14030 // ---------------------------------------------------------------------------
14031 // TOneRoute
14032 // ---------------------------------------------------------------------------
14033 
14034 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14035 {
14036 /* General:
14037  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14038  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14039  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14040  route will use automatic signals or not.
14041  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14042  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14043  elements, so additional work is needed to complete all their members before they are ready for conversion into
14044  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14045  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14046  ConvertAndAdd.......
14047 */
14048  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14049  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14050  ClearRoute();
14051  int TrackVectorPosition;
14052  TTrackElement TrackElement;
14053  TPrefDirElement FirstElement, LastElement;
14054 
14055  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14056  {
14057  Utilities->CallLogPop(199);
14058  return(false);
14059  }
14060  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14061  {
14062  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14063  Utilities->CallLogPop(1996);
14064  return(false);
14065  }
14066  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14067  {
14068  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14069  Utilities->CallLogPop(200);
14070  return(false);
14071  }
14072  if(Track->IsLCAtHV(18, HLoc, VLoc))
14073  {
14074  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14075  Utilities->CallLogPop(1909);
14076  return(false);
14077  }
14078 // check if selected a train & disallow if so
14079  if(TrackElement.TrainIDOnElement > -1)
14080  {
14081  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14082  Utilities->CallLogPop(202);
14083  return(false);
14084  }
14085 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14086  TPrefDirElement PrefDirElement;
14087  int LockedVectorNumber;
14088 
14089  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14090  {
14091  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14092  Utilities->CallLogPop(203);
14093  return(false);
14094  }
14095  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14096  {
14097  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14098  Utilities->CallLogPop(204);
14099  return(false);
14100  }
14102  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14103 // signal in an autosig route & follow with a non-autosig route
14104 
14105  TPrefDirElement BlankElement;
14106 
14107  StartElement1 = BlankElement;
14108  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14109 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14110  bool InPrefDirFlag = false;
14111 
14112  bool FoundFlag;
14113  int PrefDirPos0 = -1;
14114  int PrefDirPos1 = -1;
14115  int PrefDirPos2 = -1;
14116  int PrefDirPos3 = -1;
14117 
14119  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14120  int PrefDirVecPos[4] =
14121  {
14122  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14123  };
14124 
14125  for(int x = 0; x < 4; x++)
14126  {
14127  int b = PrefDirVecPos[x];
14128  if(b > -1)
14129  {
14130  // only allow the appropriate exit route to be searched
14131  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14132  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14133  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14134  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14135  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14136  {
14137  InPrefDirFlag = true;
14138  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14139  if(AutoSigsFlag)
14140  {
14141  StartElement1.AutoSignals = true;
14142  }
14143  StartElement1.PrefDirRoute = true;
14144  }
14145  }
14146  }
14147 
14148  if(!InPrefDirFlag)
14149  {
14151  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14152  Utilities->CallLogPop(205);
14153  return(false);
14154  }
14155 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14157  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14158 
14159  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14160  {
14161  throw Exception("Selection in two routes - should never happen!");
14162  }
14163  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14164  {
14165  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14166  {
14167  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14168  Utilities->CallLogPop(206);
14169  return(false);
14170  }
14171  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14172  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14173  {
14174  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14175  Utilities->CallLogPop(207);
14176  return(false);
14177  }
14178  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14179  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14180  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14181  {
14182  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14183  Utilities->CallLogPop(208);
14184  return(false);
14185  }
14186  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14188  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14189  if(AutoSigsFlag)
14190  {
14191  StartElement1.AutoSignals = true;
14192  }
14193  StartElement1.PrefDirRoute = true;
14195  Utilities->CallLogPop(209);
14196  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14197  }
14198 
14199  else // no route started
14200  {
14201 // check if selected position is adjacent to start or end of an existing route and disallow
14202  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14203  {
14204  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14205  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14206  {
14207  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14208  Utilities->CallLogPop(210);
14209  return(false);
14210  }
14211  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14212  {
14213  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14214  Utilities->CallLogPop(211);
14215  return(false);
14216  }
14217  }
14218 
14219 // check if it's adjacent to end of an an existing route,
14220  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14221  {
14223  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14224  {
14225  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14226  Utilities->CallLogPop(212);
14227  return(false);
14228  }
14229  }
14230  SearchVector.push_back(StartElement1);
14231  Utilities->CallLogPop(213);
14232  return(true);
14233  }
14234 }
14235 
14236 // ---------------------------------------------------------------------------
14237 
14238 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14239  IDInt &ReqPosRouteID, bool &PointsChanged)
14240 
14241 /*
14242  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14243 
14244  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14245  this being set to -1 for not used.
14246  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14247  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14248  Check correct type of element - signal/buffers/continuation.
14249  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14250  EndElement2 corresponding to the 2 possible PrefDir elements).
14251  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14252  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14253  linked forward to another route.
14254  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14255  for same position as start should cover this)
14256 
14257  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14258  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14259  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14260  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14261  If the search fails then return false.
14262  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14263  in the SearchVector to ensure it's entered as part of the new route.
14264  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14265  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14266  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14267  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14268  so return false, with an appropriate message if ConsecSignalsRoute set.
14269 */
14270 
14271 {
14272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14273  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14274  int EndPosition; // the position selected
14275 
14276  Track->LCFoundInAutoSigsRoute = false;
14278  TotalSearchCount = 0;
14279  ReqPosRouteID = IDInt(-1); // default value for not used
14280  TTrackElement TrackElement;
14281  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14282  // given element as can't select 2-track elements
14283  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14284  {
14285  Utilities->CallLogPop(214);
14286  return(false);
14287  }
14288  if(Track->IsLCAtHV(19, HLoc, VLoc))
14289  {
14290  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14291  Utilities->CallLogPop(1908);
14292  return(false);
14293  }
14294 // cancel selection if on original start element
14295  if(EndPosition == StartRoutePosition)
14296  {
14297  Utilities->CallLogPop(215);
14298  return(false);
14299  }
14300  if(AutoSigsFlag)
14301  {
14302  if(TrackElement.TrackType == Buffers)
14303  {
14304  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14305  Utilities->CallLogPop(216);
14306  return(false);
14307  }
14308  }
14309  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14310  {
14311  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14312  Utilities->CallLogPop(217);
14313  return(false);
14314  }
14315 // check if train on element
14316  if(TrackElement.TrainIDOnElement > -1)
14317  {
14318  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14319  Utilities->CallLogPop(219);
14320  return(false);
14321  }
14322 // disallow if not in EveryPrefDir & set EndElement(s)
14323  bool InPrefDirFlag = false;
14324 
14325  bool FoundFlag;
14326  int PrefDirPos0 = -1;
14327  int PrefDirPos1 = -1;
14328  int PrefDirPos2 = -1;
14329  int PrefDirPos3 = -1;
14330 
14331  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14332  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14333  int PrefDirVecPos[4] =
14334  {
14335  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14336  };
14337 
14338  for(int x = 0; x < 4; x++)
14339  {
14340  int b = PrefDirVecPos[x];
14341  if(b > -1)
14342  {
14343  InPrefDirFlag = true;
14344  if(EndElement1.TrackVectorPosition == -1)
14345  {
14346  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14347  }
14348  else
14349  {
14350  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14351  }
14352  }
14353  }
14354  if(!InPrefDirFlag)
14355  {
14357  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14358  Utilities->CallLogPop(220);
14359  return(false);
14360  }
14361 // check if in an existing route - can't be a bridge so can use a simple 'find'
14362 // bool InRoute = false;
14364  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14365 
14366  if(RoutePair.first > -1)
14367  {
14368  if(RoutePair.second != 0) // not first element in existing route so no good
14369  {
14370  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14371  Utilities->CallLogPop(221);
14372  return(false);
14373  }
14374  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14375 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14376  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14377  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14378  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14379  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14380  {
14381  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14382  Utilities->CallLogPop(222);
14383  return(false);
14384  }
14385  EndElement1 = RouteElement;
14386  EndElement2 = BlankElement; // only need the route element
14387  EndPosition = EndElement1.TrackVectorPosition;
14388  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14389  }
14390 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14391 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14392 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14393 
14394  if(EndElement1.HLoc >= StartElement1.HLoc)
14395  {
14397  SearchLimitHighH = EndElement1.HLoc + 15;
14398  }
14399  else
14400  {
14401  SearchLimitLowH = EndElement1.HLoc - 15;
14403  }
14404  if(EndElement1.VLoc >= StartElement1.VLoc)
14405  {
14407  SearchLimitHighV = EndElement1.VLoc + 15;
14408  }
14409  else
14410  {
14411  SearchLimitLowV = EndElement1.VLoc - 15;
14413  }
14414 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14415  check & TotalSearchCounts check
14416  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14417  {
14418  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14419  Utilities->CallLogPop(1693);
14420  return false;
14421  }
14422 */
14423 // check if adjacent to start and disallow
14424  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14425  {
14427  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14428 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14429 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14430  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14431  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14432  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14433  {
14434  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14435  Utilities->CallLogPop(223);
14436  return(false);
14437  }
14438 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14439 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14440  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14441  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14442  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14443  {
14444  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14445  Utilities->CallLogPop(224);
14446  return(false);
14447  }
14448 // check if adjacent to end of a route & disallow
14450  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14451  {
14452  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14453  Utilities->CallLogPop(225);
14454  return(false);
14455  }
14456  }
14457 
14458 // check for same route as start element
14460  {
14461  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14462  Utilities->CallLogPop(226);
14463  return(false);
14464  }
14465 // check for a looping route
14466  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14467  {
14469  {
14470  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14471  Utilities->CallLogPop(1844);
14472  return(false);
14473  }
14474  }
14475 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14476 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14477 // and don't want to add it again
14478  if(StartSelectionRouteID > -1)
14479  {
14480  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14481  AutoSigsFlag))
14482  {
14483  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14484  if(PointsToBeChanged(5))
14485  {
14486  PointsChanged = true;
14487  }
14488  Utilities->CallLogPop(227);
14489  return(true);
14490  }
14491  else if(!Track->SuppressRouteFailMessage)
14492  {
14493  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14495  Utilities->CallLogPop(228);
14496  return(false);
14497  }
14498  }
14499  else
14500  {
14501 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14502 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14503 
14504 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14505 // note that a blank element will have XLinkPos set to -1
14506  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14507  {
14508  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14509  AutoSigsFlag))
14510  {
14511  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14512  if(PointsToBeChanged(6))
14513  {
14514  PointsChanged = true;
14515  }
14516  Utilities->CallLogPop(229);
14517  return(true);
14518  }
14519  else
14520  {
14522  {
14524  }
14525  Utilities->CallLogPop(230);
14526  return(false);
14527  }
14528  }
14529  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14530  {
14531  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14532  AutoSigsFlag))
14533  {
14534  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14535  if(PointsToBeChanged(7))
14536  {
14537  PointsChanged = true;
14538  }
14539  Utilities->CallLogPop(231);
14540  return(true);
14541  }
14542  else
14543  {
14545  {
14547  }
14548  Utilities->CallLogPop(232);
14549  return(false);
14550  }
14551  }
14552  // now start off in the best direction
14553  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14554  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14555  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14556  // unless new problems are found.
14557  if(StartElement1.XLinkPos == BestPos)
14558  {
14559  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14560  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14561  AutoSigsFlag))
14562  {
14563  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14564  if(PointsToBeChanged(8))
14565  {
14566  PointsChanged = true;
14567  }
14568  Utilities->CallLogPop(233);
14569  return(true);
14570  }
14571  else if(StartElement2.TrackVectorPosition > -1)
14572  {
14573  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14574  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14575  AutoSigsFlag))
14576  {
14577  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14578  if(PointsToBeChanged(9))
14579  {
14580  PointsChanged = true;
14581  }
14582  Utilities->CallLogPop(234);
14583  return(true);
14584  }
14585  }
14586  }
14587  else if(StartElement2.TrackVectorPosition > -1)
14588  {
14589  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14590  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14591  AutoSigsFlag))
14592  {
14593  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14594  if(PointsToBeChanged(10))
14595  {
14596  ;
14597  }
14598  {
14599  PointsChanged = true;
14600  }
14601  Utilities->CallLogPop(1857);
14602  return(true);
14603  }
14604  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14605  AutoSigsFlag))
14606  {
14607  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14608  if(PointsToBeChanged(11))
14609  {
14610  ;
14611  }
14612  {
14613  PointsChanged = true;
14614  }
14615  Utilities->CallLogPop(1858);
14616  return(true);
14617  }
14618  }
14619  else if(StartElement1.XLinkPos == (1 - BestPos))
14620  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14621  {
14622  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14623  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14624  AutoSigsFlag))
14625  {
14626  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14627  if(PointsToBeChanged(12))
14628  {
14629  PointsChanged = true;
14630  }
14631  Utilities->CallLogPop(1864);
14632  return(true);
14633  }
14634  }
14635  }
14637  {
14639  }
14640  Utilities->CallLogPop(235);
14641  return(false);
14642 }
14643 
14644 // ---------------------------------------------------------------------------
14645 
14646 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14647 {
14648  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14649  if(PrefDirSize() == 0)
14650  {
14651  Utilities->CallLogPop(1704);
14652  return;
14653  }
14654  for(unsigned int x = 0; x < PrefDirSize(); x++)
14655  {
14656  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14657  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14658  {
14659  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14660  TempPrefDirElement.EXGraphicPtr);
14661  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14662  {
14663  if(x == 0)
14664  {
14665  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14666  TempPrefDirElement.EntryDirectionGraphicPtr);
14667  }
14668  if(x == (PrefDirSize() - 1))
14669  {
14670  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14671  TempPrefDirElement.EntryDirectionGraphicPtr);
14672  }
14673  }
14674  }
14675  }
14676 
14677  Utilities->CallLogPop(1705);
14678 }
14679 
14680 // ---------------------------------------------------------------------------
14681 
14682 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14683  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14684 
14685 /*
14686  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14687  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14688  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14689  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14690  Return false if any element (apart from RequiredPosition) is on an existing route.
14691  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14692 
14693  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14694  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14695  added during the function so as to leave it exactly as it was on entering, then return false).
14696  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14697  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14698  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14699  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14700  the route number that the searched-for element is the start of if any, and set to -1 if no
14701  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14702  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14703  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14704  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14705 
14706  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14707  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14708  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14709  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14710  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14711  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14712  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14713  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14714  or if train on element (unless a bridge & train on different track).
14715  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14716  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14717  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14718  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14719  AutoSignals member set if AutoSigsFlag set, then return true.
14720  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14721 
14722  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14723  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14724  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14725  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14726  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14727  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14728  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14729 
14730  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14731  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14732 */
14733 
14734 {
14735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14736  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14737  AnsiString((short)AutoSigsFlag));
14738  int VectorCount = 0;
14739  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14740 
14741 // check for a fouled diagonal for first element. Added for v1.3.2
14742  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14743  {
14744  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14745  {
14746  for(int x = 0; x < VectorCount; x++)
14747  {
14748  SearchVector.erase(SearchVector.end() - 1);
14749  }
14750  Utilities->CallLogPop(2043);
14751  return(false);
14752  }
14753  }
14754  bool FirstPass = true;
14755 
14756  while(true)
14757  {
14758  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14759  {
14760  Track->LCFoundInAutoSigsRoute = true;
14761  }
14762  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14763  {
14764  for(int x = 0; x < VectorCount; x++)
14765  {
14766  SearchVector.erase(SearchVector.end() - 1);
14767  }
14768  Utilities->CallLogPop(1926);
14769  return(false);
14770  }
14771  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14772  {
14773  for(int x = 0; x < VectorCount; x++)
14774  {
14775  SearchVector.erase(SearchVector.end() - 1);
14776  }
14777  Utilities->CallLogPop(236);
14778  return(false);
14779  }
14780  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14781  // reached a valid signal that isn't the required position, user should always select the next
14782  // signal in a route so have to fail
14783  // won't affect recurive searches as for them the first pass element is always a point
14784  {
14785  for(int x = 0; x < VectorCount; x++)
14786  {
14787  SearchVector.erase(SearchVector.end() - 1);
14788  }
14789  Utilities->CallLogPop(237);
14790  return(false);
14791  }
14792  FirstPass = false;
14793  int NextPosition = PrefDirElement.Conn[XLinkPos];
14794  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14795  TPrefDirElement SearchElement(NextTrackElement);
14796  SearchElement.TrackVectorPosition = NextPosition;
14797  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14798  SearchElement.ELinkPos = NextELinkPos;
14799  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14800  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14801  int NextXLinkPos;
14802  if(SearchElement.ELinkPos == 0)
14803  {
14804  NextXLinkPos = 1;
14805  }
14806  if(SearchElement.ELinkPos == 1)
14807  {
14808  NextXLinkPos = 0;
14809  }
14810  if(SearchElement.ELinkPos == 2)
14811  {
14812  NextXLinkPos = 3;
14813  }
14814  if(SearchElement.ELinkPos == 3)
14815  {
14816  NextXLinkPos = 2;
14817  }
14818  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14819  {
14820  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14821 // note that may be buffers, continuation or gap
14822  SearchElement.XLinkPos = NextXLinkPos;
14823  }
14824 // can't set XLink or XLinkPos yet if the element is a leading point.
14825 
14826 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14827  for(unsigned int x = 0; x < SearchVector.size(); x++)
14828  {
14829  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14830  {
14831  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14832  // OK if a bridge & routes on different tracks
14833  {
14834  for(int x = 0; x < VectorCount; x++)
14835  {
14836  SearchVector.erase(SearchVector.end() - 1);
14837  }
14838  Utilities->CallLogPop(238);
14839  return(false);
14840  }
14841  }
14842  }
14843 
14844 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14845  TAllRoutes::TRouteElementPair SecondPair;
14847  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14848  if(RoutePair.first > -1)
14849  {
14850  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14851  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
14852  RoutePair.second).ELinkPos)))
14853  {
14854  // still OK if start of an expected route
14855  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
14856  {
14857  for(int x = 0; x < VectorCount; x++)
14858  {
14859  SearchVector.erase(SearchVector.end() - 1);
14860  }
14861  Utilities->CallLogPop(239);
14862  return(false); // only allow for start of an expected route
14863  }
14864  }
14865  }
14866  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14867  {
14868  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14869  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
14870  SecondPair.second).ELinkPos)))
14871  {
14872  // still OK if start of an expected route
14873  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
14874  {
14875  for(int x = 0; x < VectorCount; x++)
14876  {
14877  SearchVector.erase(SearchVector.end() - 1);
14878  }
14879  Utilities->CallLogPop(240);
14880  return(false); // only allow for start of an expected route
14881  }
14882  }
14883  }
14884 // check if a train on element, unless a bridge & train on different track
14885 // OK of same train as start element - no drop this
14886 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14887  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14888  {
14889  for(int x = 0; x < VectorCount; x++)
14890  {
14891  SearchVector.erase(SearchVector.end() - 1);
14892  }
14893  Utilities->CallLogPop(241);
14894  return(false);
14895  }
14896  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14897  {
14898  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14899  {
14900  for(int x = 0; x < VectorCount; x++)
14901  {
14902  SearchVector.erase(SearchVector.end() - 1);
14903  }
14904  Utilities->CallLogPop(242);
14905  return(false);
14906  }
14907  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14908  {
14909  for(int x = 0; x < VectorCount; x++)
14910  {
14911  SearchVector.erase(SearchVector.end() - 1);
14912  }
14913  Utilities->CallLogPop(243);
14914  return(false);
14915  }
14916  }
14917 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
14918  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14919  {
14920  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14921  {
14922  for(int x = 0; x < VectorCount; x++)
14923  {
14924  SearchVector.erase(SearchVector.end() - 1);
14925  }
14926  Utilities->CallLogPop(244);
14927  return(false);
14928  }
14929  }
14930 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
14931 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
14932  bool InPrefDirFlag = false;
14933  PrefDirElement1 = BlankElement;
14934  PrefDirElement2 = BlankElement;
14935 
14936  bool FoundFlag;
14937  int PrefDirPos0 = -1;
14938  int PrefDirPos1 = -1;
14939  int PrefDirPos2 = -1;
14940  int PrefDirPos3 = -1;
14942  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14943  int PrefDirVecPos[4] =
14944  {
14945  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14946  };
14947  for(int x = 0; x < 4; x++)
14948  {
14949  int b = PrefDirVecPos[x];
14950  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
14951  {
14952  InPrefDirFlag = true;
14953  if(PrefDirElement1.TrackVectorPosition == -1)
14954  {
14955  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
14956  }
14957  else
14958  {
14959  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
14960  }
14961  }
14962  }
14963  if(!InPrefDirFlag)
14964  {
14965  for(int x = 0; x < VectorCount; x++)
14966  {
14967  SearchVector.erase(SearchVector.end() - 1);
14968  }
14969  Utilities->CallLogPop(245);
14970  return(false);
14971  }
14972 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14973 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14974 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14976  {
14977  for(int x = 0; x < VectorCount; x++)
14978  {
14979  SearchVector.erase(SearchVector.end() - 1);
14980  }
14981  Utilities->CallLogPop(1690);
14982  return(false);
14983  }
14984 // check if found it
14985  if(SearchElement.TrackVectorPosition == RequiredPosition)
14986  {
14987 // need to ensure a signal/buffer/continuation
14988  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
14989  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
14990  {
14991  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
14993  for(int x = 0; x < VectorCount; x++)
14994  {
14995  SearchVector.erase(SearchVector.end() - 1);
14996  }
14997  Utilities->CallLogPop(246);
14998  return(false);
14999  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15000 
15001  if(AutoSigsFlag)
15002  {
15003  PrefDirElement1.AutoSignals = true;
15004  }
15005  PrefDirElement1.PrefDirRoute = true;
15007  {
15009  {
15010  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15012  }
15013  for(int x = 0; x < VectorCount; x++)
15014  {
15015  SearchVector.erase(SearchVector.end() - 1);
15016  }
15017  Utilities->CallLogPop(1928);
15018  return(false);
15019  }
15020  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15021  VectorCount++; // not really needed but include for tidyness
15022  TotalSearchCount++;
15023  Utilities->CallLogPop(247);
15024  return(true);
15025  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15026 
15027 // check if a buffer or continuation (end of search on this leg if not found by now)
15028  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15029  {
15030  for(int x = 0; x < VectorCount; x++)
15031  {
15032  SearchVector.erase(SearchVector.end() - 1);
15033  }
15034  Utilities->CallLogPop(248);
15035  return(false);
15036  }
15037 // check if SearchVector exceeds a size of 150
15038  if(SearchVector.size() > 150)
15039  {
15040  for(int x = 0; x < VectorCount; x++)
15041  {
15042  SearchVector.erase(SearchVector.end() - 1);
15043  }
15044  Utilities->CallLogPop(1420);
15045  return(false);
15046  }
15047 // check if reached a leading point
15048  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15049  {
15050 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15051  int SearchPos1 = SearchElement.Attribute + 1;
15052  int SearchPos2;
15053  if(SearchPos1 == 2)
15054  {
15055  SearchPos1++;
15056  }
15057  if(SearchPos1 == 1)
15058  {
15059  SearchPos2 = 3;
15060  }
15061  else
15062  {
15063  SearchPos2 = 1;
15064  }
15065  SearchElement.XLink = SearchElement.Link[SearchPos1];
15066  SearchElement.XLinkPos = SearchPos1;
15067  InPrefDirFlag = false;
15068  if(SearchElement.XLink == PrefDirElement1.XLink)
15069  {
15070  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15071  InPrefDirFlag = true;
15072  }
15073  else if(SearchElement.XLink == PrefDirElement2.XLink)
15074  {
15075  SearchElement = PrefDirElement2;
15076  InPrefDirFlag = true;
15077  }
15078 // push element with XLink set to position [SearchPos1] if on a PrefDir
15079  if(InPrefDirFlag)
15080  {
15081 // check for a fouled diagonal for leading point for XLinkPos == 1)
15082  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15083  {
15084  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15085  {
15086  for(int x = 0; x < VectorCount; x++)
15087  {
15088  SearchVector.erase(SearchVector.end() - 1);
15089  }
15090  Utilities->CallLogPop(249);
15091  return(false);
15092  }
15093  }
15094  if(AutoSigsFlag)
15095  {
15096  SearchElement.AutoSignals = true;
15097  }
15098  SearchElement.PrefDirRoute = true;
15099  SearchVector.push_back(SearchElement);
15100  VectorCount++;
15101  TotalSearchCount++;
15102 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15103  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15104  AutoSigsFlag))
15105  {
15107  {
15109  {
15110  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15112  }
15113  for(int x = 0; x < VectorCount; x++)
15114  {
15115  SearchVector.erase(SearchVector.end() - 1);
15116  }
15117  Utilities->CallLogPop(1929);
15118  return(false);
15119  }
15120  Utilities->CallLogPop(250);
15121  return(true);
15122  }
15123  else
15124  {
15125 // remove leading point with XLinkPos [1]
15126  SearchVector.erase(SearchVector.end() - 1);
15127  VectorCount--;
15128  }
15129  }
15130 // XLink set to position [SearchPos2]
15131  SearchElement.XLink = SearchElement.Link[SearchPos2];
15132  SearchElement.XLinkPos = SearchPos2;
15133  if(SearchElement.XLink == PrefDirElement1.XLink)
15134  {
15135  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15136  }
15137  else if(SearchElement.XLink == PrefDirElement2.XLink)
15138  {
15139  SearchElement = PrefDirElement2;
15140  }
15141  else // failed to find a valid exit from the point
15142  {
15143  for(int x = 0; x < VectorCount; x++)
15144  {
15145  SearchVector.erase(SearchVector.end() - 1);
15146  }
15147  Utilities->CallLogPop(251);
15148  return(false);
15149  }
15150 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15151  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15152  {
15153  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15154  {
15155  for(int x = 0; x < VectorCount; x++)
15156  {
15157  SearchVector.erase(SearchVector.end() - 1);
15158  }
15159  Utilities->CallLogPop(252);
15160  return(false);
15161  }
15162  }
15163 // push element with XLink set to position [SearchPos2]
15164  if(AutoSigsFlag)
15165  {
15166  SearchElement.AutoSignals = true;
15167  }
15168  SearchElement.PrefDirRoute = true;
15169  SearchVector.push_back(SearchElement);
15170  VectorCount++;
15171  TotalSearchCount++;
15172 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15173  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15174  AutoSigsFlag))
15175  {
15177  {
15179  {
15180  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15182  }
15183  for(int x = 0; x < VectorCount; x++)
15184  {
15185  SearchVector.erase(SearchVector.end() - 1);
15186  }
15187  Utilities->CallLogPop(1930);
15188  return(false);
15189  }
15190  Utilities->CallLogPop(1592);
15191  return(true);
15192  }
15193  else
15194  {
15195  for(int x = 0; x < VectorCount; x++)
15196  {
15197  SearchVector.erase(SearchVector.end() - 1);
15198  }
15199  Utilities->CallLogPop(253);
15200  return(false);
15201  }
15202  } // if leading point
15203 
15204 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15205  SearchElement = PrefDirElement1;
15206  if(AutoSigsFlag)
15207  {
15208  SearchElement.AutoSignals = true;
15209  }
15210  SearchElement.PrefDirRoute = true;
15211  SearchVector.push_back(SearchElement);
15212  VectorCount++;
15213  TotalSearchCount++;
15214  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15215  PrefDirElement = SearchElement;
15216  } // while(true)
15217 }
15218 
15219 // ---------------------------------------------------------------------------
15220 
15221 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15222 {
15223 /*
15224  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15225  and the new or extended route created from that. Hence action varies depending on whether
15226  it is a completely new route, or an extension of an existing route at the beginning or the end.
15227  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15228  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15229 
15230  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15231  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15232  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15233  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15234  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15235  is decremented;
15236  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15237  from the existing route, then enter the new route into the AllRoutesVector;
15238  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15239  then enter the new route into the AllRoutesVector.
15240 
15241  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15242  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15243  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15244  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15245  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15246  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15247  for the new route and return;
15248  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15249  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15250 
15251  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15252  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15253  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15254 
15255 */
15256  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15257  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15258  if(SearchVector.size() < 1)
15259  {
15260  Utilities->CallLogPop(254);
15261  return;
15262  }
15264  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15265  {
15266  Utilities->CallLogPop(255);
15267  return;
15268  }
15269  TAllRoutes::TLockedRouteClass LockedRouteObject;
15270 
15272  unsigned int TruncatePrefDirPosition = 0;
15273 
15274  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15275 /* if have ReqPosRouteID:
15276  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15277  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15278  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15279  the existing route, then enter the new route into the AllRoutesVector
15280  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15281  then enter the new route into the AllRoutesVector
15282 */
15283  {
15286  {
15287  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15288  x++) // start at 1 as first element already in SearchVector
15289  {
15291  }
15292  // note that route numbers in map adjusted when ReqPos route cleared
15294  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15295  // set during ClearRouteDuringRouteBuildingAt
15297  {
15300  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15301  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15302  }
15303  }
15305  {
15307  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15308  }
15310  {
15311  SearchVector.pop_back();
15312  }
15313  }
15314  if(StartSelectionRouteID > -1)
15315 /* if have StartSelectionRouteID:
15316  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15317  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15318  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15319  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15320  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15321 */
15322  {
15324  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15325  {
15328  {
15329  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15330  for(unsigned int x = 0; x < SearchVector.size(); x++)
15331  {
15333  RouteNumber, GetFixedSearchElementAt(3, x));
15334  // find & store locked route truncate position in PrefDirVector for later use
15336  {
15337  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15338  {
15339  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15340  }
15341  }
15342  }
15344  {
15345  throw Exception("Error - failed to validate extended route for preferred route");
15346  }
15349  if(!AutoSigsFlag)
15350  {
15351  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15352  }
15353  // now add the reinstated locked route if required and set signals accordingly
15355  {
15356  LockedRouteObject.RouteNumber = RouteNumber;
15357  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15358  // now reset the signals for the locked route
15359  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15360  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15361  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15362  {
15363  // return all signals to red in route section to be truncated
15364  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15365  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15366  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15367  {
15368  TrackElement.Attribute = 0;
15369  Track->PlotSignal(10, TrackElement, Display);
15370  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15371  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15372  }
15373  }
15374  }
15375  AllRoutes->CheckMapAndRoutes(1); // test
15376  Utilities->CallLogPop(256);
15377  return;
15378  }
15380  {
15383  RouteElement.AutoSignals = true;
15384  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15385  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15386  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15387  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15388  }
15389  }
15390  else
15391  {
15393  }
15394 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15395 // AllRoutesVector hence nothing to do here
15396  }
15397  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15398  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15399  {
15400  throw Exception("Error - failed to validate single route for preferred route");
15401  }
15402  AllRoutes->StoreOneRoute(1, this);
15403  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15404  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15405  if(!AutoSigsFlag)
15406  {
15407  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15408  }
15409  AllRoutes->CheckMapAndRoutes(2); // test
15410  Utilities->CallLogPop(257);
15411 }
15412 
15413 // ---------------------------------------------------------------------------
15414 
15415 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15416 {
15417 /*
15418  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15419  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15420  & ensure signal/buffers/continuation.
15421  Note that can't select ConsecSignalsRoute for non-preferred routes.
15422  Check if train on element & disallow.
15423  Set default values for retained parameters:-
15424  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15425  StartSelectionRouteID = route that selection starts in if there is one;
15426 
15427  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15428  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15429  validity. This is just for safety reasons, the PrefDir values aren't used.
15430  StartElement1 & 2 are set to these PrefDirelements.
15431 
15432  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15433 
15434  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15435  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15436  blank StartElement2 (only want to use the route element), then return true.
15437  Check if adjacent to start or end of an existing route & disallow if so.
15438  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15439  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15440  SetRemainingSearchVectorValues().
15441  Finally add the required element to the SearchVector & return true.
15442 
15443 */
15444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15445  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15446  ClearRoute();
15447  int TrackVectorPosition;
15448  TTrackElement TrackElement;
15449  TPrefDirElement FirstElement, LastElement;
15450 
15451  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15452  {
15453  Utilities->CallLogPop(258);
15454  return(false);
15455  }
15456  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15457  {
15458  if(!Callon)
15459  {
15460  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15461  }
15462 // makes later adjacent route checks too complicated
15463  Utilities->CallLogPop(259);
15464  return(false);
15465  }
15466  if(Track->IsLCAtHV(21, HLoc, VLoc))
15467  {
15468  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15469  Utilities->CallLogPop(1910);
15470  return(false);
15471  }
15472 // check if selected a train & disallow if so
15473  if(TrackElement.TrainIDOnElement > -1)
15474  {
15475  if(!Callon)
15476  {
15477  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15478  }
15479  Utilities->CallLogPop(260);
15480  return(false);
15481  }
15482 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15483  TPrefDirElement PrefDirElement;
15484  int LockedVectorNumber;
15485 
15486  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15487  {
15488  if(!Callon)
15489  {
15490  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15491  }
15492  Utilities->CallLogPop(261);
15493  return(false);
15494  }
15495  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15496  {
15497  if(!Callon)
15498  {
15499  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15500  }
15501  Utilities->CallLogPop(262);
15502  return(false);
15503  }
15505 // AdjacentStartRouteNumber = -1;
15506  StartRoutePosition = TrackVectorPosition;
15507 // StartRouteSelectPosition = TrackVectorPosition;
15508 
15509  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15510  TPrefDirElement PrefDirElement2(TrackElement);
15511 
15512  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15513  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15514  TPrefDirElement BlankElement;
15515 
15516  PrefDirElement1.ELinkPos = 0;
15517  PrefDirElement1.XLinkPos = 1;
15518  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15519  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15520  if(!(PrefDirElement1.EntryExitNumber()))
15521  {
15522  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15523  // no need for bridge check as bridge selections not allowed
15524  }
15525  PrefDirElement1.CheckCount = 9;
15526  PrefDirElement2.ELinkPos = 1;
15527  PrefDirElement2.XLinkPos = 0;
15528  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15529  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15530  if(!(PrefDirElement2.EntryExitNumber()))
15531  {
15532  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15533  }
15534  PrefDirElement2.CheckCount = 9; // both now set
15535 
15536 // set StartElements to the above PrefDirElements
15537  StartElement1 = PrefDirElement1;
15538  StartElement2 = PrefDirElement2;
15539 
15540 // no PrefDir check needed as doesn't need to be in a PrefDir
15541 
15542 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15544  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15545 
15546  if(RoutePair.first > -1)
15547  {
15548  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15549  {
15550  if(!Callon)
15551  {
15552  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15553  }
15554  Utilities->CallLogPop(263);
15555  return(false);
15556  }
15557  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15558  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15559  {
15560  if(!Callon)
15561  {
15562  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15563  }
15564  Utilities->CallLogPop(264);
15565  return(false);
15566  }
15567  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15568  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15569  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15570  {
15571  if(!Callon)
15572  {
15573  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15574  }
15575  Utilities->CallLogPop(265);
15576  return(false);
15577  }
15578  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15580  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15581  StartElement2 = BlankElement; // only use the route element
15583  Utilities->CallLogPop(266);
15584  return(true); // all retained values set
15585  }
15586 
15587  else // selection not in an existing route
15588  {
15589 // check if it's adjacent to start of an an existing route,
15590  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15591  {
15592  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15593  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15594  {
15595  if(!Callon)
15596  {
15597  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15598  }
15599  Utilities->CallLogPop(267);
15600  return(false);
15601  }
15602  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15603  {
15604  if(!Callon)
15605  {
15606  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15607  }
15608  Utilities->CallLogPop(268);
15609  return(false);
15610  }
15611  }
15612 // check if it's adjacent to end of an an existing route,
15613  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15614  {
15616  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15617  {
15618  if(!Callon)
15619  {
15620  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15621  }
15622  Utilities->CallLogPop(269);
15623  return(false);
15624  }
15625  }
15626  // not in a route or adjacent to start or end of a route
15627  // in this case reset all variable values to -1 & CheckCount to 4
15628  StartElement1.ELink = -1;
15629  StartElement1.ELinkPos = -1;
15630  StartElement1.XLink = -1;
15631  StartElement1.XLinkPos = -1;
15632  StartElement1.EXNumber = -1;
15634  StartElement2 = BlankElement;
15635  SearchVector.push_back(StartElement1);
15636  Utilities->CallLogPop(270);
15637  return(true);
15638  }
15639 }
15640 
15641 // ---------------------------------------------------------------------------
15642 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15643 
15644 /*
15645  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15646 
15647  Declare the following integers:-
15648  EndPosition - TrackVectorPosition for the selection;
15649  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15650  Check if selection is a valid track element and set EndPosition.
15651  Cancel if select original start element, then check that not points, bridge or crossover.
15652  Check & fail if a train is present at the selection.
15653  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15654  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15655  No check needed for selection in EveryPrefDir.
15656  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15657  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15658  as don't need it if in a route.
15659  Check if selection adj to start or end of a route and disallow.
15660  Fail if select same route as starting route, though should already have failed earlier if this is so.
15661 
15662  If there's a StartSelectionRouteID then StartElement1 will be set to
15663  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15664  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15665  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15666  to add the new route to the AllRoutesVectorPtr.
15667  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15668  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15669  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15670  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15671  the search vector values and return.
15672  If not returned yet then have failed to find the required element so return false with no message.
15673 
15674 */
15675 
15676 {
15677 // get EndPosition
15678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15679  AnsiString(VLoc));
15680  int EndPosition;
15681 
15682  TotalSearchCount = 0;
15683  ReqPosRouteID = IDInt(-1); // for not used
15684  TTrackElement TrackElement;
15685  TPrefDirElement BlankElement;
15686 
15687  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15688  {
15689  Utilities->CallLogPop(271);
15690  return(false);
15691  }
15692 // EndPosition = EndSelectPosition;
15693 // cancel selection if on original start element
15694  if(EndPosition == StartRoutePosition)
15695  {
15696  Utilities->CallLogPop(272);
15697  return(false);
15698  }
15699  if(Track->IsLCAtHV(22, HLoc, VLoc))
15700  {
15701  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15702  Utilities->CallLogPop(1911);
15703  return(false);
15704  }
15705  if((TrackElement.TrackType == Points) && !Callon)
15706  {
15707  if(!Callon)
15708  {
15709  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15710  }
15711 // makes later adjacent route checks too complicated
15712  Utilities->CallLogPop(273);
15713  return(false);
15714  }
15715  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15716  {
15717  if(!Callon)
15718  {
15719  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15720  }
15721 // makes later adjacent route checks too complicated
15722  Utilities->CallLogPop(1861);
15723  return(false);
15724  }
15725 // check if train on element
15726  if(TrackElement.TrainIDOnElement > -1)
15727  {
15728  if(!Callon)
15729  {
15730  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15731  }
15732  Utilities->CallLogPop(274);
15733  return(false);
15734  }
15735 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15736 // check passed)
15737  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15738  TPrefDirElement EndElement2(TrackElement);
15739 
15740  EndElement1.TrackVectorPosition = EndPosition;
15741  EndElement2.TrackVectorPosition = EndPosition;
15742  EndElement1.ELinkPos = 0;
15743  EndElement1.XLinkPos = 1;
15744  EndElement1.ELink = EndElement1.Link[0];
15745  EndElement1.XLink = EndElement1.Link[1];
15746  if(!(EndElement1.EntryExitNumber()))
15747  {
15748  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15749  }
15750  EndElement1.CheckCount = 9;
15751  EndElement2.ELinkPos = 1;
15752  EndElement2.XLinkPos = 0;
15753  EndElement2.ELink = EndElement2.Link[1];
15754  EndElement2.XLink = EndElement2.Link[0];
15755  if(!(EndElement2.EntryExitNumber()))
15756  {
15757  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15758  }
15759  EndElement2.CheckCount = 9; // both now set
15760 
15761 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15762 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15763 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15764 
15765  if(EndElement1.HLoc >= StartElement1.HLoc)
15766  {
15768  SearchLimitHighH = EndElement1.HLoc + 15;
15769  }
15770  else
15771  {
15772  SearchLimitLowH = EndElement1.HLoc - 15;
15774  }
15775  if(EndElement1.VLoc >= StartElement1.VLoc)
15776  {
15778  SearchLimitHighV = EndElement1.VLoc + 15;
15779  }
15780  else
15781  {
15782  SearchLimitLowV = EndElement1.VLoc - 15;
15784  }
15785 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15786  check & TotalSearchCounts check
15787  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15788  {
15789  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15790  Utilities->CallLogPop(1694);
15791  return false;
15792  }
15793 */
15794 // don't need EveryPrefDir check for NonPreferredRoute
15795 
15796 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15797 // bool InRoute = false;
15799  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15800 
15801  if(RoutePair.first > -1)
15802  {
15803  if(RoutePair.second != 0) // not first element in existing route so no good
15804  {
15805  if(!Callon)
15806  {
15807  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15808  }
15809  Utilities->CallLogPop(275);
15810  return(false);
15811  }
15812  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15813 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15814  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15815  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15816  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15817  {
15818  if(!Callon)
15819  {
15820  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15821  }
15822  Utilities->CallLogPop(276);
15823  return(false);
15824  }
15825  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
15826  EndElement2 = BlankElement; // only need the route element
15827  EndPosition = EndElement1.TrackVectorPosition;
15828  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
15829  }
15830 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
15831  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15832  {
15833  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
15834  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
15835 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15836 // && (AdjPosition != StartRoutePosition))
15837  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15838  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15839  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
15840  {
15841  if(!Callon)
15842  {
15843  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
15844  }
15845  Utilities->CallLogPop(277);
15846  return(false);
15847  }
15848 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15849 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
15850  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15851  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15852  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
15853  (AdjPosition != StartRoutePosition))
15854  {
15855  if(!Callon)
15856  {
15857  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
15858  }
15859  Utilities->CallLogPop(278);
15860  return(false);
15861  }
15862 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
15864  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
15865  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
15866  {
15867  if(!Callon)
15868  {
15869  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
15870  }
15871  Utilities->CallLogPop(279);
15872  return(false);
15873  }
15874  }
15875 
15876 // check for same route as start element
15878  {
15879  if(!Callon)
15880  {
15881  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
15882  }
15883  Utilities->CallLogPop(280);
15884  return(false);
15885  }
15886 // check for a looping route
15887  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15888  {
15890  {
15891  if(!Callon)
15892  {
15893  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
15894  }
15895  Utilities->CallLogPop(1845);
15896  return(false);
15897  }
15898  }
15899 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15900 // so search from this element.
15901 
15902  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
15903 
15904  if(StartSelectionRouteID > -1)
15905  {
15906  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
15907  {
15909  if(PointsToBeChanged(0))
15910  {
15911  PointsChanged = true;
15912  }
15913  Utilities->CallLogPop(281);
15914  return(true);
15915  }
15916  else
15917  {
15918  if(!Callon)
15919  {
15921  }
15922  Utilities->CallLogPop(282);
15923  return(false);
15924  }
15925  }
15926  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
15927  // search on the 2 ways out of the element, which has to be a 2-ended element
15928  {
15929 // check if selection adjacent to start element and if so use that
15930  if(SearchVector.at(0).Conn[0] == EndPosition)
15931  {
15932  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
15933  {
15935  if(PointsToBeChanged(1))
15936  {
15937  PointsChanged = true;
15938  }
15939  Utilities->CallLogPop(283);
15940  return(true);
15941  }
15942  else
15943  {
15944  if(!Callon)
15945  {
15947  }
15948  Utilities->CallLogPop(284);
15949  return(false);
15950  }
15951  }
15952  else if(SearchVector.at(0).Conn[1] == EndPosition)
15953  {
15954  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
15955  {
15957  if(PointsToBeChanged(2))
15958  {
15959  PointsChanged = true;
15960  }
15961  Utilities->CallLogPop(285);
15962  return(true);
15963  }
15964  else
15965  {
15966  if(!Callon)
15967  {
15969  }
15970  Utilities->CallLogPop(286);
15971  return(false);
15972  }
15973  }
15974  // now start off in the best direction
15975  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
15976 
15977  if(SearchVector.at(0).Config[BestPos] != End)
15978  {
15979  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15980  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
15981  {
15983  if(PointsToBeChanged(3))
15984  {
15985  PointsChanged = true;
15986  }
15987  Utilities->CallLogPop(287);
15988  return(true);
15989  }
15990  }
15991  if(SearchVector.at(0).Config[1 - BestPos] != End)
15992  {
15993  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15994  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
15995  {
15997  if(PointsToBeChanged(4))
15998  {
15999  PointsChanged = true;
16000  }
16001  Utilities->CallLogPop(288);
16002  return(true);
16003  }
16004  }
16005  }
16006  if(!Callon)
16007  {
16009  }
16010  Utilities->CallLogPop(289);
16011  return(false);
16012 }
16013 
16014 // ---------------------------------------------------------------------------
16015 
16016 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16017 /*
16018  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16019  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16020  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16021  Keep a count of entries in SearchVector during the current function call, so that this number can be
16022  erased for an unproductive branch search.
16023  First check (within the loop) whether XLink leads to an End & return false if so.
16024  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16025  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16026  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16027  train on element (unless a bridge & train on different track), or if element
16028  fouls an existing diagonal route (except if element is a leading point - these checked later).
16029  Then check if found required element. If so save it & return true.
16030  If not the required element check if buffer or continuation, & if so erase all searchvector
16031  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16032  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16033  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16034  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16035  When return true have 8 items from CheckCount established, only waiting for EXNumber
16036 */
16037 {
16038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16039  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16040  int VectorCount = 0;
16041 
16042 // check for a fouled diagonal for first element. Added for v1.3.2
16043  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16044  (CurrentTrackElement.Link[XLinkPos] == 9))
16045  {
16046  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16047  {
16048  for(int x = 0; x < VectorCount; x++)
16049  {
16050  SearchVector.erase(SearchVector.end() - 1);
16051  }
16052  Utilities->CallLogPop(2044);
16053  return(false);
16054  }
16055  }
16056  while(true)
16057  {
16058  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16059  {
16060  for(int x = 0; x < VectorCount; x++)
16061  {
16062  SearchVector.erase(SearchVector.end() - 1);
16063  }
16064  Utilities->CallLogPop(1927);
16065  return(false);
16066  }
16067  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16068  {
16069  for(int x = 0; x < VectorCount; x++)
16070  {
16071  SearchVector.erase(SearchVector.end() - 1);
16072  }
16073  Utilities->CallLogPop(290);
16074  return(false);
16075  }
16076  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16077  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16078  TPrefDirElement SearchElement(NextTrackElement);
16079  SearchElement.TrackVectorPosition = NextPosition;
16080  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16081  SearchElement.ELinkPos = NextELinkPos;
16082  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16083  int NextXLinkPos;
16084  if(SearchElement.ELinkPos == 0)
16085  {
16086  NextXLinkPos = 1;
16087  }
16088  if(SearchElement.ELinkPos == 1)
16089  {
16090  NextXLinkPos = 0;
16091  }
16092  if(SearchElement.ELinkPos == 2)
16093  {
16094  NextXLinkPos = 3;
16095  }
16096  if(SearchElement.ELinkPos == 3)
16097  {
16098  NextXLinkPos = 2;
16099  }
16100  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16101  {
16102  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16103  // but may be buffers, continuation or gap
16104  SearchElement.XLinkPos = NextXLinkPos;
16105  }
16106 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16107 // can't set XLink or XLinkPos yet if the element is a leading point.
16108 
16109 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16110  for(unsigned int x = 0; x < SearchVector.size(); x++)
16111  {
16112  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16113  {
16114  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16115  // OK if it's a bridge & routes on different tracks
16116  {
16117  for(int x = 0; x < VectorCount; x++)
16118  {
16119  SearchVector.erase(SearchVector.end() - 1);
16120  }
16121  Utilities->CallLogPop(291);
16122  return(false);
16123  }
16124  }
16125  }
16126 
16127 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16128  TAllRoutes::TRouteElementPair SecondPair;
16130  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16131  if(RoutePair.first > -1)
16132  {
16133  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16134  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16135  RoutePair.second).ELinkPos)))
16136  {
16137  // still OK if start of an expected route
16138  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16139  {
16140  for(int x = 0; x < VectorCount; x++)
16141  {
16142  SearchVector.erase(SearchVector.end() - 1);
16143  }
16144  Utilities->CallLogPop(292);
16145  return(false); // only allow for start of an expected route
16146  }
16147  }
16148  }
16149  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16150  {
16151  // OK if it's a bridge & routes on different tracks
16152  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16153  SecondPair.second).ELinkPos)))
16154  {
16155  // still OK if start of an expected route
16156  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16157  {
16158  for(int x = 0; x < VectorCount; x++)
16159  {
16160  SearchVector.erase(SearchVector.end() - 1);
16161  }
16162  Utilities->CallLogPop(293);
16163  return(false); // only allow for start of an expected route
16164  }
16165  }
16166  }
16167 // check if a train on element, unless a bridge & train on different track
16168 // OK of same train as start element - no, drop this
16169 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16170  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16171  {
16172  for(int x = 0; x < VectorCount; x++)
16173  {
16174  SearchVector.erase(SearchVector.end() - 1);
16175  }
16176  Utilities->CallLogPop(294);
16177  return(false);
16178  }
16179  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16180  {
16181  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16182  {
16183  for(int x = 0; x < VectorCount; x++)
16184  {
16185  SearchVector.erase(SearchVector.end() - 1);
16186  }
16187  Utilities->CallLogPop(295);
16188  return(false);
16189  }
16190  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16191  {
16192  for(int x = 0; x < VectorCount; x++)
16193  {
16194  SearchVector.erase(SearchVector.end() - 1);
16195  }
16196  Utilities->CallLogPop(296);
16197  return(false);
16198  }
16199  }
16200 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16201  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16202  {
16203  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16204  {
16205  for(int x = 0; x < VectorCount; x++)
16206  {
16207  SearchVector.erase(SearchVector.end() - 1);
16208  }
16209  Utilities->CallLogPop(297);
16210  return(false);
16211  }
16212  }
16213 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16214 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16215 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16217  {
16218  for(int x = 0; x < VectorCount; x++)
16219  {
16220  SearchVector.erase(SearchVector.end() - 1);
16221  }
16222  Utilities->CallLogPop(1689);
16223  return(false);
16224  }
16225 // check if found it
16226  if(SearchElement.TrackVectorPosition == RequiredPosition)
16227  {
16228  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16229  {
16230  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16231  {
16232  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16233  }
16234  else
16235  {
16236  SearchElement.XLinkPos = 1;
16237  }
16238 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16239  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16240  }
16241  SearchVector.push_back(SearchElement);
16242  VectorCount++; // not really needed but include for tidyness
16243  TotalSearchCount++;
16244  Utilities->CallLogPop(298);
16245  return(true);
16246  }
16247 // Not the required element - check if a buffer or continuation
16248  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16249  {
16250  for(int x = 0; x < VectorCount; x++)
16251  {
16252  SearchVector.erase(SearchVector.end() - 1);
16253  }
16254  Utilities->CallLogPop(299);
16255  return(false);
16256  }
16257 // check if SearchVector exceeds a size of 150
16258  if(SearchVector.size() > 150)
16259  {
16260  for(int x = 0; x < VectorCount; x++)
16261  {
16262  SearchVector.erase(SearchVector.end() - 1);
16263  }
16264  Utilities->CallLogPop(1421);
16265  return(false);
16266  }
16267 // check if reached a leading point
16268  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16269  {
16270 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16271  int SearchPos1 = SearchElement.Attribute + 1;
16272  int SearchPos2;
16273  if(SearchPos1 == 2)
16274  {
16275  SearchPos1++;
16276  }
16277  if(SearchPos1 == 1)
16278  {
16279  SearchPos2 = 3;
16280  }
16281  else
16282  {
16283  SearchPos2 = 1;
16284  }
16285 // push element with XLink set to position [SearchPos1]
16286  SearchElement.XLink = SearchElement.Link[SearchPos1];
16287  SearchElement.XLinkPos = SearchPos1;
16288 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16289  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16290  {
16291  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16292  {
16293  for(int x = 0; x < VectorCount; x++)
16294  {
16295  SearchVector.erase(SearchVector.end() - 1);
16296  }
16297  Utilities->CallLogPop(300);
16298  return(false);
16299  }
16300  }
16301  SearchVector.push_back(SearchElement);
16302  VectorCount++;
16303  TotalSearchCount++;
16304 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16305 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16306 // recursive search as has to be a TTrackElement for non-preferred route searches
16307  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16308  {
16309  Utilities->CallLogPop(301);
16310  return(true);
16311  }
16312  else
16313  {
16314 // remove leading point with XLinkPos [SearchPos1]
16315  SearchVector.erase(SearchVector.end() - 1);
16316  VectorCount--;
16317 // push element with XLink set to position [SearchPos2]
16318  SearchElement.XLink = SearchElement.Link[SearchPos2];
16319  SearchElement.XLinkPos = SearchPos2;
16320 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16321  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16322  {
16323  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16324  {
16325  for(int x = 0; x < VectorCount; x++)
16326  {
16327  SearchVector.erase(SearchVector.end() - 1);
16328  }
16329  Utilities->CallLogPop(302);
16330  return(false);
16331  }
16332  }
16333  SearchVector.push_back(SearchElement);
16334  VectorCount++;
16335  TotalSearchCount++;
16336 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16337  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16338  {
16339  Utilities->CallLogPop(303);
16340  return(true);
16341  }
16342  else
16343  {
16344  for(int x = 0; x < VectorCount; x++)
16345  {
16346  SearchVector.erase(SearchVector.end() - 1);
16347  }
16348  Utilities->CallLogPop(304);
16349  return(false);
16350  }
16351  }
16352  } // if leading point
16353 
16354 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16355 // ready for next element on route
16356  SearchVector.push_back(SearchElement);
16357  VectorCount++;
16358  TotalSearchCount++;
16359  CurrentTrackElement = SearchElement;
16360  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16361  } // while(true)
16362 }
16363 
16364 // ---------------------------------------------------------------------------
16365 
16367 
16368 /*
16369  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16370  having all values set (since not necessarily on PrefDirs).
16371  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16372  (if it was the start), so these are checked first and set if necessary. All elements now have
16373  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16374  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16375  to set the route colour and direction graphics.
16376 */
16377 
16378 {
16379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16380  if(SearchVector.size() == 0)
16381  {
16382  throw Exception("Error, SearchVector empty");
16383  }
16384 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16385 // hence need to examine and update it if necessary
16386  TPrefDirElement SecondElement;
16387 
16388  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16389  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16390  // need above check or SecondElement will fail
16391  {
16392  SecondElement = SearchVector.at(1);
16393  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16394  for(int x = 0; x < 4; x++)
16395  {
16396  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16397  {
16398  if(SearchVector.at(0).XLink == -1) // i.e. not set
16399  {
16400  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16401  SearchVector.at(0).XLinkPos = x;
16402  }
16403  int ELinkPos;
16404  if(SearchVector.at(0).XLinkPos == 0)
16405  {
16406  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16407  }
16408  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16409  if(SearchVector.at(0).XLinkPos == 1)
16410  {
16411  ELinkPos = 0;
16412  }
16413  if(SearchVector.at(0).XLinkPos == 2)
16414  {
16415  ELinkPos = 3;
16416  }
16417  if(SearchVector.at(0).XLinkPos == 3)
16418  {
16419  ELinkPos = 2;
16420  }
16421  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16422  {
16423  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16424  SearchVector.at(0).ELinkPos = ELinkPos;
16425  }
16426  break; // no point going any further
16427  }
16428  }
16429  }
16430  for(unsigned int x = 0; x < SearchVector.size(); x++)
16431  {
16432  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16433 // set EXNumber
16434  if(!(SearchVector.at(x).EntryExitNumber()))
16435  {
16436  throw Exception("Error in EntryExitNumber 3");
16437  }
16438  SearchVector.at(x).CheckCount++;
16439 // all values now incorporated
16440  }
16441 
16442  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16443 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16444 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16445  Utilities->CallLogPop(305);
16446 }
16447 
16448 // ---------------------------------------------------------------------------
16449 
16451 
16452 /*
16453  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16454  AutoSigsRoute.
16455  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16456  beginning or the end.
16457  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16458  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16459  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16460  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16461  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16462  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16463  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16464 
16465  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16466  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16467  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16468  route at the start.
16469 
16470  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16471  for the new route and return.
16472 */
16473 
16474 {
16475  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16476  AnsiString(ReqPosRouteID.GetInt()));
16477  if(SearchVector.size() < 1)
16478  {
16479  Utilities->CallLogPop(306);
16480  return;
16481  }
16482  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16483  if(!ValidatePrefDir(6))
16484  {
16485  Utilities->CallLogPop(307);
16486  return;
16487  }
16488  TAllRoutes::TLockedRouteClass LockedRouteObject;
16489 
16491  unsigned int TruncatePrefDirPosition = 0;
16492 
16493  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16494 /* if have ReqPosRouteID:
16495  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16496  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16497  then enter the new route into the AllRoutesVector
16498 */
16499  {
16501  {
16502  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16503  x++) // start at 1 as first element already in SearchVector
16504  {
16506  }
16507  // note that route numbers in map adjusted when ReqPos route cleared
16509  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16510  // set during ClearRouteDuringRouteBuildingAt)
16512  {
16515  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16516  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16517  }
16518  }
16520  {
16521  SearchVector.pop_back();
16522  }
16523  }
16524  if(StartSelectionRouteID > -1)
16525 /* if have StartSelectionRouteID:
16526  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16527  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16528 */
16529  {
16531  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16532  {
16534  {
16535  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16536  for(unsigned int x = 0; x < SearchVector.size(); x++)
16537  {
16539  RouteNumber, GetFixedSearchElementAt(7, x));
16540  // find & store locked route truncate position in PrefDirVector for later use
16542  {
16543  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16544  {
16545  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16546  }
16547  }
16548  }
16550  {
16551  throw Exception("Failed to validate extended route for nonpreferred route");
16552  }
16555  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16556  // now add the reinstated locked route if required and set signals accordingly
16557  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16558  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16559  // that I haven't thought of
16561  {
16562  LockedRouteObject.RouteNumber = RouteNumber;
16563  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16564  // now reset the signals for the locked route
16565  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16566  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16567  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16568  {
16569  // return all signals to red in route section to be truncated
16570  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16571  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16572  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16573  {
16574  TrackElement.Attribute = 0;
16575  Track->PlotSignal(11, TrackElement, Display);
16576  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16577  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16578  }
16579  }
16580  }
16581  AllRoutes->CheckMapAndRoutes(3); // test
16582  Utilities->CallLogPop(308);
16583  return;
16584  }
16585  }
16586  else
16587  {
16589  }
16590 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16591 // hence nothing to do here
16592  }
16593  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16594  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16595  {
16596  throw Exception("Failed to validate single route for nonpreferred route");
16597  }
16598  AllRoutes->StoreOneRoute(2, this);
16599  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16600  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16601  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16602  AllRoutes->CheckMapAndRoutes(4); // test
16603  Utilities->CallLogPop(309);
16604 }
16605 
16606 // ---------------------------------------------------------------------------
16607 
16608 void TOneRoute::SetRoutePoints(int Caller) const
16609 /*
16610  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16611  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16612  when they were created.
16613 */
16614 {
16615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16616  if(!PrefDirVector.empty())
16617  {
16618  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16619  {
16620  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16621  {
16622  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16623  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16624  }
16625  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16626  {
16627  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16628  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16629  }
16630  }
16631  }
16632  Utilities->CallLogPop(327);
16633 }
16634 
16635 // ---------------------------------------------------------------------------
16636 
16637 void TOneRoute::SetRouteSignals(int Caller) const
16638 /* Used for new train additions in AddTrain and in route setting
16639  Set the signals as follows:-
16640  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16641  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16642  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16643  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16644  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16645  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16646  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16647  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16648  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16649 
16650  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16651  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16652  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16653  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16654  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16655  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16656  as a green signal.
16657 */
16658 {
16659  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16660  if(!PrefDirVector.empty())
16661  {
16662  // get target Attribute value, check first if there is a forward linked route
16663  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16664  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16665  int ForwardLinkedRouteNumber, Attribute = 0;
16666  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16667  // Note that LastElement can't be points but can be linked to points
16668  {
16669  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16670  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16671  {
16672  if(ForwardLinkedRouteNumber > -1)
16673  {
16674  int NextForwardLinkedRouteNumber = -1;
16675  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16676  Attribute)))
16677  {
16678  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16679  }
16680  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16681  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16682  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16683  }
16684  }
16685  }
16686  int RouteNumber;
16687  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16688  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16689  if(RouteType != TAllRoutes::NoRoute)
16690  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16691  {
16692  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16693  }
16694  }
16695  Utilities->CallLogPop(1720);
16696 }
16697 
16698 // ---------------------------------------------------------------------------
16699 
16700 bool TOneRoute::PointsToBeChanged(int Caller) const
16701 {
16702  // true if at any point in SearchVector points have to be changed
16703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16704  if(!SearchVector.empty())
16705  {
16706  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16707  {
16708  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16709  {
16710  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16711  {
16712  Utilities->CallLogPop(1717);
16713  return(true);
16714  }
16715  }
16716  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16717  {
16718  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16719  {
16720  Utilities->CallLogPop(1718);
16721  return(true);
16722  }
16723  }
16724  }
16725  }
16726  Utilities->CallLogPop(1719);
16727  return(false);
16728 }
16729 
16730 // ---------------------------------------------------------------------------
16731 
16732 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16733 /*
16734  Works forward through the route until finds:-
16735  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16736  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16737  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16738  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16739  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16740  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16741  returns true;
16742  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16743 */
16744 {
16745  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16746  Attribute = 0;
16747  NextForwardLinkedRouteNumber = -1;
16748  for(unsigned int x = 0; x < PrefDirSize(); x++)
16749  {
16750  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16751  if(PrefDirVector.at(x).TrackType == Bridge)
16752  {
16753  if(PrefDirVector.at(x).XLinkPos < 2)
16754  {
16755  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16756  }
16757  else
16758  {
16759  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16760  }
16761  }
16762  if(TrainID != -1)
16763  {
16764  Utilities->CallLogPop(328);
16765  return(true);
16766  }
16767  if(PrefDirVector.at(x).TrackType == Buffers)
16768  {
16769  Attribute = 1;
16770  Utilities->CallLogPop(329);
16771  return(true);
16772  }
16773  if(PrefDirVector.at(x).TrackType == Continuation)
16774  {
16775  Attribute = 3;
16776  Utilities->CallLogPop(330);
16777  return(true);
16778  }
16779  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16780  {
16781  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16782  {
16783  Attribute = 0;
16784  Utilities->CallLogPop(1950);
16785  return(true);
16786  }
16787  }
16788  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16789  {
16790  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16791  if(Attribute > 3)
16792  {
16793  Attribute = 3;
16794  }
16795  Utilities->CallLogPop(331);
16796  return(true);
16797  }
16798  if(x == PrefDirSize() - 1)
16799  {
16800  TPrefDirElement LastElement = PrefDirVector.at(x);
16801  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16802  {
16803  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16804  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16805  {
16806  Attribute = 0;
16807  Utilities->CallLogPop(332);
16808  return(false);
16809  }
16810  }
16811  }
16812  }
16813  Utilities->CallLogPop(333);
16814  return(true);
16815 }
16816 
16817 // ---------------------------------------------------------------------------
16818 
16819 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16820 /*
16821  This function is only called by TAllRoutes::SetAllRearwardsSignals.
16822 
16823  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16824  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16825  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16826  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16827  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16828  a route.
16829 
16830  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16831  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16832  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
16833  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
16834  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
16835  reference. If no train is found before the beginning of the route is reached the function returns true
16836 
16837  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
16838  and the next rearwards signal becomes yellow, although it's the first in the route
16839 */
16840 {
16841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
16842  AnsiString(PrefDirVectorStartPosition));
16843  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
16844  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
16845 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
16846 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
16847  bool SkipContinuationAndBufferAttributeChange = false;
16848 
16849  if(!PrefDirVector.empty())
16850  {
16851  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
16852  {
16853  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16854  if(PrefDirPtr->TrackType == Bridge)
16855  {
16856  if(PrefDirPtr->XLinkPos < 2)
16857  {
16858  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16859  }
16860  else
16861  {
16862  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16863  }
16864  }
16865  if(TrainID != -1)
16866  {
16867  SkipContinuationAndBufferAttributeChange = true;
16868  break;
16869  }
16870  }
16871 
16874  {
16875  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
16876  AutoSigVectorIT++)
16877  {
16878  if(!AllRoutes->AllRoutesVector.empty())
16879  {
16880  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
16881  {
16882  SkipContinuationAndBufferAttributeChange = true;
16883  break;
16884  }
16885  }
16886  }
16887  }
16889  {
16890  SkipContinuationAndBufferAttributeChange = true;
16891  }
16892  if(!SkipContinuationAndBufferAttributeChange)
16893  {
16894  if(PrefDirVector.back().TrackType == Buffers)
16895  {
16896  Attribute = 1; // treat buffer as red signal
16897  }
16898  if(PrefDirVector.back().TrackType == Continuation)
16899  {
16900  Attribute = 3; // treat continuation as a green signal
16901  }
16902  }
16903  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16904  {
16905  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16906  if(PrefDirPtr->TrackType == Bridge)
16907  {
16908  if(PrefDirPtr->XLinkPos < 2)
16909  {
16910  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16911  }
16912  else
16913  {
16914  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16915  }
16916  }
16917  if(TrainID != -1)
16918  {
16919  Utilities->CallLogPop(334);
16920  return(false);
16921  }
16922  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
16923  // the attribute to 0 so first signal behind the LC is red
16924  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16925  {
16926  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16927  {
16928  Attribute = 0;
16929  }
16930  }
16931 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
16932 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
16933  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
16934  {
16935  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
16936  PrefDirPtr->PrefDirRoute)
16937  {
16938 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
16939 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
16940  int LockedVecNum = 0; //not used
16941  TPrefDirElement DummyPrefDir; //not used
16942  bool KeepAttributeAt0ForLockedRoute = false;
16943  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
16944  LockedVecNum))
16945  {
16946  Attribute = 0;
16947  KeepAttributeAt0ForLockedRoute = true;
16948  }
16949 //end of addition
16950  if(Attribute < 3)
16951  {
16952  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
16953  }
16954  else
16955  {
16956  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
16957  }
16958  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
16959  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
16960  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
16961  {
16962  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16963  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
16964  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16965  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
16966  }
16967  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
16968  {
16969  Attribute++;
16970  }
16971  Display->Update(); // update after recent plots
16972  }
16973  }
16974  }
16975  }
16976  Utilities->CallLogPop(335);
16977  return(true);
16978 }
16979 
16980 // ---------------------------------------------------------------------------
16981 
16982 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
16983 /*
16984  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
16985  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
16986  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
16987  Selection invalid if select a bridge; trying to leave a single element; last element to be left
16988  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
16989  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
16990  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
16991  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
16992 */
16993 {
16994  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16995  "," + AnsiString((short)PrefDirRoute));
16996  bool ElementInRoute = false;
16997  bool TrainOccupyingRoute = false;
16998 
16999  for(unsigned int b = 0; b < PrefDirSize(); b++)
17000  {
17001  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17002  {
17003  ElementInRoute = true;
17004  break;
17005  }
17006  }
17007  if(!ElementInRoute)
17008  {
17009  ReturnFlag = NotInRoute;
17010  Utilities->CallLogPop(336);
17011  return;
17012  }
17013 // it is in the route so continue, first look for a train or a flashing level crossing
17014  for(int b = PrefDirSize() - 1; b >= 0; b--)
17015  {
17016  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17017  if(PrefDirVector.at(b).TrackType == Bridge)
17018  {
17019  if(PrefDirVector.at(b).XLinkPos < 2)
17020  {
17021  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17022  }
17023  else
17024  {
17025  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17026  }
17027  }
17028  if(TrainID != -1)
17029  {
17030 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17031 // ReturnFlag = InRouteFalse;
17032 // Utilities->CallLogPop(337);
17033 // return;
17034 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17035  TrainOccupyingRoute = true; // train is forward of the truncate point
17036  }
17037  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17038  {
17039  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17040  ReturnFlag = InRouteFalse;
17041  Utilities->CallLogPop(1941);
17042  return;
17043  }
17044  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17045  {
17046  break; // OK found truncate element & no flashing LC in front
17047  }
17048  }
17049 
17050  for(unsigned int b = 0; b < PrefDirSize(); b++)
17051  {
17052  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17053  {
17054  if(PrefDirVector.at(b).TrackType == Bridge)
17055  {
17056  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17057  ReturnFlag = InRouteFalse;
17058  Utilities->CallLogPop(338);
17059  return;
17060  }
17061  if(b == 1)
17062  {
17063  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17064  ReturnFlag = InRouteFalse;
17065  Utilities->CallLogPop(339);
17066  return;
17067  }
17068  if(b > 0)
17069  {
17070  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17071  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17072  {
17073  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17074  {
17075  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17076  ReturnFlag = InRouteFalse;
17077  Utilities->CallLogPop(340);
17078  return;
17079  }
17080  }
17081  else
17082  {
17083  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17084  {
17085  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17086  ReturnFlag = InRouteFalse;
17087  Utilities->CallLogPop(341);
17088  return;
17089  }
17090  }
17091  }
17092  int RouteNumber;
17094 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17095 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17096 
17097 // check if part of this route already locked & disallow if so
17098  if(!(AllRoutes->LockedRouteVector.empty()))
17099  {
17101  {
17102  if(LRVIT->RouteNumber == RouteNumber)
17103  {
17104  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17105  ReturnFlag = InRouteFalse;
17106  Utilities->CallLogPop(749);
17107  return;
17108  }
17109  }
17110  }
17111  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17112  // RouteLockingRequired only checks for trains approaching
17113  {
17116  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17117  L"Warning!", MB_YESNO | MB_ICONWARNING);
17118  TrainController->BaseTime = TDateTime::CurrentDateTime();
17120  if(button == IDNO)
17121  {
17122  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17123  Utilities->CallLogPop(342);
17124  return;
17125  }
17126  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17127  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17128  TAllRoutes::TLockedRouteClass LockedRoute;
17129  bool ExistingLockedRouteModified = false;
17130  LockedRoute.RouteNumber = RouteNumber;
17131  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17132  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17133  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17134  LockedRoute.LockStartTime = TrainController->TTClockTime;
17135 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17136 // to use the new TruncateTrackVectorPosition & LockStartTime
17137  if(!AllRoutes->LockedRouteVector.empty())
17138  {
17139  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17140  LRVIT++)
17141  {
17142  if(LRVIT->RouteNumber == RouteNumber)
17143  {
17144  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17145  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17146  ExistingLockedRouteModified = true;
17147  }
17148  }
17149  }
17150  if(!ExistingLockedRouteModified)
17151  {
17152  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17153  }
17154  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17155  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17156  {
17157  // return all signals to red in route section to be truncated
17158  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17159  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17160  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17161  {
17162  TrackElement.Attribute = 0;
17163  Track->PlotSignal(2, TrackElement, Display);
17164  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17165  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17166  }
17167  }
17168 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17169  ReturnFlag = InRouteTrue;
17170  }
17171  else
17172  {
17173  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17174  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17175  {
17176  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17177  ReturnFlag = InRouteTrue;
17178  }
17179  }
17180  AllRoutes->CheckMapAndRoutes(5); // test
17181  Utilities->CallLogPop(343);
17182  return;
17183  }
17184  }
17185  ReturnFlag = NotInRoute;
17186  Utilities->CallLogPop(344);
17187 }
17188 
17189 // ---------------------------------------------------------------------------
17191 /*
17192  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17193  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17194  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17195  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17196  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17197  the route colours.
17198 */
17199 {
17200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17201  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17203  int RouteNumber;
17204  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17205  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17206 
17207  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17208  {
17209  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17210  {
17211  if(PrefDirVector.at(x).TrackType == SignalPost)
17212  {
17213  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17214  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17215  }
17216  }
17217  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17218 // already set all signals to red in route so start at start of route for further rearwards signal setting
17219  }
17220  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17221  {
17222  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17223  }
17224  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17225  AllRoutes->CheckMapAndRoutes(9); // test
17226  TrainController->BaseTime = TDateTime::CurrentDateTime();
17228  Utilities->CallLogPop(345);
17229  return;
17230 }
17231 
17232 // ---------------------------------------------------------------------------
17233 
17234 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17235 /*
17236  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17237 */
17238 {
17239  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17240  AnsiString((short)PrefDirRoute));
17241  if(SearchVector.empty())
17242  {
17243  Utilities->CallLogPop(1149);
17244  return;
17245  }
17246  for(unsigned int b = 0; b < SearchVector.size(); b++)
17247  {
17250  PrefDirRoute);
17251  }
17252  Utilities->CallLogPop(346);
17253 }
17254 
17255 // ---------------------------------------------------------------------------
17256 
17257 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17258 /*
17259  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17260  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17261  TOneRoute.
17262 */
17263 {
17264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17265  AnsiString((short)PrefDirRoute));
17266  RouteFlash.RouteFlashVector.clear();
17267  TRouteFlashElement RouteFlashElement;
17268 
17269  for(unsigned int b = 0; b < SearchVector.size(); b++)
17270  {
17271  int H = GetFixedSearchElementAt(11, b).HLoc;
17272  int V = GetFixedSearchElementAt(12, b).VLoc;
17274  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17275  RouteFlashElement.HLoc = H;
17276  RouteFlashElement.VLoc = V;
17278  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17279  }
17280  Utilities->CallLogPop(348);
17281 }
17282 
17283 // ---------------------------------------------------------------------------
17284 
17285 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17286 {
17287  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17288  if(!PrefDirVector.empty())
17289  {
17290  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17291  {
17292  int H = PrefDirPtr->HLoc;
17293  int V = PrefDirPtr->VLoc;
17294  // check for any LCs that are closed to trains & set the flash values and store in the vector
17295  if(Track->IsLCAtHV(39, H, V))
17296  {
17297  if(Track->IsLCBarrierUpAtHV(0, H, V))
17298  {
17299  Track->LCChangeFlag = true;
17300  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17301  CLC.HLoc = H;
17302  CLC.VLoc = V;
17304  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17307  if(PrefDirRoute)
17308  {
17309  CLC.TypeOfRoute = 1;
17310  }
17311  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17312  Track->ChangingLCVector.push_back(CLC);
17313  }
17314  }
17315  }
17316  }
17317  Utilities->CallLogPop(1948);
17318 }
17319 
17320 // ---------------------------------------------------------------------------
17321 
17323 /*
17324  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17325  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17326  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17327  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17328 */
17329 {
17330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17331  if(!OverlayPlotted)
17332  {
17333  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17334  {
17335  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17336  {
17337  continue;
17338  }
17339  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17340  Display->Update();
17341  }
17342  OverlayPlotted = true;
17343  }
17344  Utilities->CallLogPop(349);
17345 }
17346 
17347 // ---------------------------------------------------------------------------
17348 
17350 /*
17351  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17352  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17353  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17354  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17355 */
17356 {
17357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17358  if(OverlayPlotted)
17359  {
17360  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17361  {
17362  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17363  {
17364  continue;
17365  }
17366  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17367  Display->Update();
17368  }
17369  OverlayPlotted = false;
17370  }
17371  Utilities->CallLogPop(350);
17372 }
17373 
17374 // ---------------------------------------------------------------------------
17375 
17376 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17377 {
17378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17379  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17380  {
17381  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17382  }
17383  Utilities->CallLogPop(120);
17384  return(AllRoutesVector.at(At));
17385 }
17386 
17387 // ---------------------------------------------------------------------------
17388 // ---------------------------------------------------------------------------
17389 
17391 {
17392  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17393  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17394  {
17395  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17396  }
17397  Utilities->CallLogPop(121);
17398  return(AllRoutesVector.at(At));
17399 }
17400 
17401 // ---------------------------------------------------------------------------
17402 
17403 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17404 /*
17405  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17406 */
17407 {
17408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17409  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17410  {
17411  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17412  }
17413  Utilities->CallLogPop(351);
17414 }
17415 
17416 // ---------------------------------------------------------------------------
17417 
17418 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17419 {
17420  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17421  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17422  {
17423  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17424  }
17425  Utilities->CallLogPop(1706);
17426 }
17427 
17428 // ---------------------------------------------------------------------------
17429 
17430 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17431 /*
17432  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17433  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17434  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17435  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17436  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17437  length (train length).
17438 */
17439 {
17440  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17441  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17442  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17443  {
17444  TTruncateReturnType ReturnFlag;
17445  RouteTruncateFlag = true;
17446 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17447  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17448  RouteTruncateFlag = false;
17449  if(ReturnFlag == NotInRoute)
17450  {
17451  continue;
17452  }
17453  else if(ReturnFlag == InRouteTrue)
17454  {
17455  Utilities->CallLogPop(352);
17456  return(true);
17457  }
17458  else if(ReturnFlag == InRouteFalse)
17459  {
17460  Utilities->CallLogPop(353);
17461  return(false);
17462  }
17463  }
17464  Utilities->CallLogPop(354);
17465  return(false);
17466 }
17467 
17468 // ---------------------------------------------------------------------------
17469 
17470 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17471 /*
17472  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17473  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17474 */
17475 {
17476  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17477  AnsiString(LinkPos));
17478  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17479  {
17480  Utilities->CallLogPop(355);
17481  return(false);
17482  }
17483  THVPair Route2MultiMapKeyPair;
17484 
17485  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17486  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17487  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17488  TRoute2MultiMapIterator Route2MultiMapIterator;
17489 
17490  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17491  {
17492  Utilities->CallLogPop(356);
17493  return(false);
17494  }
17495  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17496  {
17497  Utilities->CallLogPop(1422);
17498  return(true);
17499  }
17500  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17501  {
17502  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17503 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17504 // realised after writing this that can't be points as would have been covered above, but leave anyway
17505  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17506  Route2MultiMapIterator->second.second);
17507  EntryLinkPos = PrefDirElement1.ELinkPos;
17508  ExitLinkPos = PrefDirElement1.XLinkPos;
17509  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17510  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17511  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17512  {
17513  Utilities->CallLogPop(357);
17514  return(true);
17515  }
17516  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17517  {
17518  Utilities->CallLogPop(358);
17519  return(true);
17520  }
17521  }
17522  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17523  {
17524  Utilities->CallLogPop(1423);
17525  return(true);
17526  }
17527  Utilities->CallLogPop(363);
17528  return(false); // none found
17529 }
17530 
17531 // ---------------------------------------------------------------------------
17532 
17533 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17534  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17535 /*
17536  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17537  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17538  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17539  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17540  for replotting of AutoSigsRoutes.
17541 */
17542 {
17543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17544  AnsiString(LinkPos));
17545  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17546  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17547  if(TrackVectorPosition == -1)
17548  {
17549  Utilities->CallLogPop(364);
17550  return(NoRoute); // allows for continuation entries & exits
17551  }
17552  THVPair Route2MultiMapKeyPair;
17553 
17554  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17555  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17556  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17557  TRoute2MultiMapIterator Route2MultiMapIterator;
17558 
17559  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17560  {
17561  Utilities->CallLogPop(365);
17562  return(NoRoute); // none found
17563  }
17564  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17565  {
17566  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17567 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17568  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17569  Route2MultiMapIterator->second.second);
17570  EntryLinkPos = PrefDirElement1.ELinkPos;
17571  ExitLinkPos = PrefDirElement1.XLinkPos;
17572  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17573  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17574  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17575  {
17576  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17577  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17578  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17579  {
17580  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17581  }
17582  if(PrefDirElement1.AutoSignals)
17583  {
17584  Utilities->CallLogPop(366);
17585  return(AutoSigsRoute);
17586  }
17587  else
17588  {
17589  Utilities->CallLogPop(367);
17590  return(NotAutoSigsRoute);
17591  }
17592  }
17593  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17594  {
17595  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17596  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17597  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17598  {
17599  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17600  }
17601  if(PrefDirElement1.AutoSignals)
17602  {
17603  Utilities->CallLogPop(368);
17604  return(AutoSigsRoute);
17605  }
17606  else
17607  {
17608  Utilities->CallLogPop(369);
17609  return(NotAutoSigsRoute);
17610  }
17611  }
17612  }
17613  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17614  {
17615  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17616  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17617 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17618  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17619  EntryLinkPos = PrefDirElement2.ELinkPos;
17620  ExitLinkPos = PrefDirElement2.XLinkPos;
17621  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17622  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17623  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17624  {
17625  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17626  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17627  {
17628  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17629  }
17630  if(PrefDirElement2.AutoSignals)
17631  {
17632  Utilities->CallLogPop(370);
17633  return(AutoSigsRoute);
17634  }
17635  else
17636  {
17637  Utilities->CallLogPop(371);
17638  return(NotAutoSigsRoute);
17639  }
17640  }
17641  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17642  {
17643  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17644  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17645  {
17646  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17647  }
17648  if(PrefDirElement2.AutoSignals)
17649  {
17650  Utilities->CallLogPop(372);
17651  return(AutoSigsRoute);
17652  }
17653  else
17654  {
17655  Utilities->CallLogPop(373);
17656  return(NotAutoSigsRoute);
17657  }
17658  }
17659  ItPair.second--; // the second iterator points one past the last matching value
17660  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17661  EntryLinkPos = PrefDirElement3.ELinkPos;
17662  ExitLinkPos = PrefDirElement3.XLinkPos;
17663  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17664  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17665  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17666  {
17667  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17668  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17669  {
17670  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17671  }
17672  if(PrefDirElement3.AutoSignals)
17673  {
17674  Utilities->CallLogPop(374);
17675  return(AutoSigsRoute);
17676  }
17677  else
17678  {
17679  Utilities->CallLogPop(375);
17680  return(NotAutoSigsRoute);
17681  }
17682  }
17683  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17684  {
17685  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17686  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17687  {
17688  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17689  }
17690  if(PrefDirElement3.AutoSignals)
17691  {
17692  Utilities->CallLogPop(376);
17693  return(AutoSigsRoute);
17694  }
17695  else
17696  {
17697  Utilities->CallLogPop(377);
17698  return(NotAutoSigsRoute);
17699  }
17700  }
17701  }
17702  Utilities->CallLogPop(378);
17703  return(NoRoute); // none found
17704 }
17705 
17706 // ---------------------------------------------------------------------------
17707 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17708 /*
17709  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17710  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17711 */
17712 {
17713  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17714  AnsiString(LinkPos));
17715  if(TrackVectorPosition == -1)
17716  {
17717  RouteNumber = -1;
17718  Utilities->CallLogPop(379);
17719  return(NoRoute); // allows for continuation & buffer entries & exits
17720  }
17721  THVPair Route2MultiMapKeyPair;
17722 
17723  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17724  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17725  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17726  TRoute2MultiMapIterator Route2MultiMapIterator;
17727 
17728  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17729  {
17730  RouteNumber = -1;
17731  Utilities->CallLogPop(380);
17732  return(NoRoute); // none found
17733  }
17734  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17735  {
17736  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17737 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17738  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17739  Route2MultiMapIterator->second.second);
17740  EntryLinkPos = PrefDirElement1.ELinkPos;
17741  ExitLinkPos = PrefDirElement1.XLinkPos;
17742  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17743  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17744  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17745  {
17746  RouteNumber = Route2MultiMapIterator->second.first;
17747  if(PrefDirElement1.AutoSignals)
17748  {
17749  Utilities->CallLogPop(381);
17750  return(AutoSigsRoute);
17751  }
17752  else
17753  {
17754  Utilities->CallLogPop(382);
17755  return(NotAutoSigsRoute);
17756  }
17757  }
17758  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17759  {
17760  RouteNumber = Route2MultiMapIterator->second.first;
17761  if(PrefDirElement1.AutoSignals)
17762  {
17763  Utilities->CallLogPop(383);
17764  return(AutoSigsRoute);
17765  }
17766  else
17767  {
17768  Utilities->CallLogPop(384);
17769  return(NotAutoSigsRoute);
17770  }
17771  }
17772  }
17773  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17774  {
17775  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17776  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17777 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17778  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17779  EntryLinkPos = PrefDirElement2.ELinkPos;
17780  ExitLinkPos = PrefDirElement2.XLinkPos;
17781  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17782  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17783  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17784  {
17785  RouteNumber = ItPair.first->second.first;
17786  if(PrefDirElement2.AutoSignals)
17787  {
17788  Utilities->CallLogPop(385);
17789  return(AutoSigsRoute);
17790  }
17791  else
17792  {
17793  Utilities->CallLogPop(386);
17794  return(NotAutoSigsRoute);
17795  }
17796  }
17797  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17798  {
17799  RouteNumber = ItPair.first->second.first;
17800  if(PrefDirElement2.AutoSignals)
17801  {
17802  Utilities->CallLogPop(387);
17803  return(AutoSigsRoute);
17804  }
17805  else
17806  {
17807  Utilities->CallLogPop(388);
17808  return(NotAutoSigsRoute);
17809  }
17810  }
17811  ItPair.second--; // the second iterator points one past the last matching value
17812  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17813  EntryLinkPos = PrefDirElement3.ELinkPos;
17814  ExitLinkPos = PrefDirElement3.XLinkPos;
17815  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17816  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17817  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17818  {
17819  RouteNumber = ItPair.second->second.first;
17820  if(PrefDirElement3.AutoSignals)
17821  {
17822  Utilities->CallLogPop(389);
17823  return(AutoSigsRoute);
17824  }
17825  else
17826  {
17827  Utilities->CallLogPop(390);
17828  return(NotAutoSigsRoute);
17829  }
17830  }
17831  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
17832  {
17833  RouteNumber = ItPair.second->second.first;
17834  if(PrefDirElement3.AutoSignals)
17835  {
17836  Utilities->CallLogPop(391);
17837  return(AutoSigsRoute);
17838  }
17839  else
17840  {
17841  Utilities->CallLogPop(392);
17842  return(NotAutoSigsRoute);
17843  }
17844  }
17845  }
17846  RouteNumber = -1;
17847  Utilities->CallLogPop(393);
17848  return(NoRoute); // none found
17849 }
17850 
17851 // ---------------------------------------------------------------------------
17852 
17853 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
17854 /*
17855  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
17856  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
17857  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
17858  and Route2MultiMap.
17859 */
17860 {
17861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
17862  TOneRoute EmptyRoute;
17863 
17864  EmptyRoute.RouteID = NextRouteID;
17865  NextRouteID++;
17866 
17867  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17868  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17869  {
17870  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
17871  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
17872  }
17873  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
17874  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
17875 
17876  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
17877  Utilities->CallLogPop(394);
17878 }
17879 
17880 // ---------------------------------------------------------------------------
17881 
17883 /*
17884  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
17885  that is already in Route is used.
17886 */
17887 {
17888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
17889  TOneRoute EmptyRoute;
17890 
17891  EmptyRoute.RouteID = Route->RouteID;
17892 
17893  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17894  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17895  {
17896  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
17897  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
17898  }
17899  Utilities->CallLogPop(1579);
17900 }
17901 
17902 // ---------------------------------------------------------------------------
17903 
17904 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
17905 /*
17906  When attaching a new route section to an existing route, it is sometimes necessary to erase the
17907  original route and create a new composite route. This function Erases all elements in the route
17908  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
17909  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
17910  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
17911  that are greater than the route number that is removed. The LockedRouteVector as also searched
17912  and if any relate to the route that has been cleared they are erased too, but the fact that one
17913  has been found is recorded so that it can be re-established later.
17914 */
17915 {
17916  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
17917  THVPair Route2MultiMapKeyPair;
17918  TRoute2MultiMapEntry Route2MultiMapEntry;
17919  TRoute2MultiMapIterator Route2MultiMapIterator;
17920 
17921 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
17922 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
17923 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
17924 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
17925 // If so the locked route is removed from the locked vector and is lost.
17926  LockedRouteTruncateTrackVectorPosition = 0;
17927  LockedRouteLastTrackVectorPosition = 0;
17928  LockedRouteLastXLinkPos = 0;
17929  LockedRouteLockStartTime = TDateTime(0);
17930  if(!LockedRouteVector.empty())
17931  {
17932  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17933  {
17934  if(LRVIT->RouteNumber == RouteNumber)
17935  {
17936  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
17937  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
17938  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
17939  LockedRouteLockStartTime = LRVIT->LockStartTime;
17940  LockedRouteFoundDuringRouteBuilding = true;
17941  LockedRouteVector.erase(LRVIT);
17942  }
17943  }
17944  }
17945  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
17946  {
17947  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
17948  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
17949  }
17950  Utilities->CallLogPop(395);
17951 }
17952 
17953 // ---------------------------------------------------------------------------
17954 
17956  TRoute2MultiMapIterator &Route2MultiMapIterator)
17957 /*
17958  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
17959  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
17960  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
17961  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
17962  are given for failure.
17963 */
17964 {
17965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
17966  AnsiString(VLoc) + "," + AnsiString(ELink));
17967  TRouteElementPair ReturnPair;
17968 
17969  ReturnPair.first = -1;
17970  ReturnPair.second = 0;
17971  THVPair Route2MultiMapKeyPair;
17972 
17973  Route2MultiMapKeyPair.first = HLoc;
17974  Route2MultiMapKeyPair.second = VLoc;
17975  TRoute2MultiMapEntry Route2MultiMapEntry;
17976 
17977  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
17978  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17979 
17980  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17981  Route2MultiMapIterator = ItPair.first;
17982 
17983  if(ItPair.first == ItPair.second)
17984  {
17985  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
17986  }
17987  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
17988  {
17989  ReturnPair.first = ItPair.first->second.first;
17990  ReturnPair.second = ItPair.first->second.second;
17991  Route2MultiMapIterator = ItPair.first;
17992  Utilities->CallLogPop(396);
17993  return(ReturnPair);
17994  }
17995  ItPair.first++;
17996  if(ItPair.first == ItPair.second)
17997  {
17998  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
17999  }
18000  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18001  {
18002  ReturnPair.first = ItPair.first->second.first;
18003  ReturnPair.second = ItPair.first->second.second;
18004  Route2MultiMapIterator = ItPair.first;
18005  Utilities->CallLogPop(397);
18006  return(ReturnPair);
18007  }
18008  Utilities->CallLogPop(398);
18009  return(ReturnPair);
18010 }
18011 
18012 // ---------------------------------------------------------------------------
18013 
18014 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18015 /*
18016  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18017  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18018  RouteNumber (route position in AllRoutes vector is returned as a reference.
18019  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18020  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18021 */
18022 {
18023  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18024  AnsiString(VLoc) + "," + AnsiString(ELink));
18025  THVPair Route2MultiMapKeyPair;
18026 
18027  Route2MultiMapKeyPair.first = HLoc;
18028  Route2MultiMapKeyPair.second = VLoc;
18029  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18030 
18031  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18032 
18033  if(ItPair.first == ItPair.second)
18034  {
18035  RouteNumber = -1;
18036  Utilities->CallLogPop(2032);
18037  return(false);
18038  }
18039  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18040  {
18041  RouteNumber = ItPair.first->second.first;
18042  Utilities->CallLogPop(2033);
18043  return(true);
18044  }
18045  ItPair.first++;
18046 
18047  if(ItPair.first == ItPair.second)
18048  {
18049  RouteNumber = -1;
18050  Utilities->CallLogPop(2034);
18051  return(false);
18052  }
18053  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18054  {
18055  RouteNumber = ItPair.first->second.first;
18056  Utilities->CallLogPop(2035);
18057  return(true);
18058  }
18059  RouteNumber = -1;
18060  Utilities->CallLogPop(2036);
18061  return(false);
18062 }
18063 
18064 // ---------------------------------------------------------------------------
18065 
18066 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18067 /*
18068  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18069  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18070  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18071  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18072  Called by TAllRoutes::AddRouteElement.
18073 */
18074 {
18075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18076  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18077  THVPair Route2MultiMapKeyPair;
18078 
18079  Route2MultiMapKeyPair.first = HLoc;
18080  Route2MultiMapKeyPair.second = VLoc;
18081  TRoute2MultiMapEntry Route2MultiMapEntry;
18082 
18083  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18084  TRouteElementPair RouteElementPair;
18085 
18086  RouteElementPair.first = RouteNumber;
18087  RouteElementPair.second = RouteElementNumber;
18088  Route2MultiMapEntry.second = RouteElementPair;
18089 
18090  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18091  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18092  {
18093  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18094  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18095  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18096  {
18097  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18098  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18099  {
18100  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18101  }
18102  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18103  }
18104  else
18105  // same ELink so have an error
18106  {
18107  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18108  }
18109  }
18110  else
18111  {
18112  Route2MultiMap.insert(Route2MultiMapEntry);
18113  }
18114 // element at H&V not found in map so insert it
18115  Utilities->CallLogPop(399);
18116 }
18117 
18118 // ---------------------------------------------------------------------------
18119 
18121 /*
18122  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18123  and the second in the reference SecondPair. If there's only one then it's the function return
18124 */
18125 {
18126  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18127  AnsiString(VLoc));
18129 
18130  TempPair.first = -1;
18131  TempPair.second = 0;
18132  SecondPair = TempPair;
18133  TRoute2MultiMapIterator Route2MultiMapIterator;
18134  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18135  THVPair Route2MultiMapKeyPair;
18136 
18137  Route2MultiMapKeyPair.first = HLoc;
18138  Route2MultiMapKeyPair.second = VLoc;
18139  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18140  {
18141  Utilities->CallLogPop(400);
18142  return(TempPair);
18143  }
18144  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18145  {
18146  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18147  Utilities->CallLogPop(401);
18148  return(Route2MultiMapIterator->second);
18149  }
18150  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18151  {
18152  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18153  TempPair = ItRange.first->second;
18154  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18155  Utilities->CallLogPop(402);
18156  return(TempPair);
18157  }
18158  Utilities->CallLogPop(403);
18159  return(TempPair);
18160 }
18161 
18162 // ---------------------------------------------------------------------------
18163 
18164 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18165 /*
18166  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18167  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18168 */
18169 {
18170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18171  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18172  {
18173  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18174  {
18175  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18176  TAllRoutes::TRouteElementPair SecondPair;
18177  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18178  if(RouteElementPair.first == -1)
18179  // failed to find element in multimap
18180  {
18181  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18182  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18183  }
18184  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18185  // neither pair has expected route number
18186  {
18187  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18188  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18189  (AnsiString)Caller);
18190  }
18191  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18192  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18193  {
18194  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18195  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18196  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18197  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18198  }
18199  }
18200  }
18201  unsigned int SizeVal = 0;
18202 
18203 // check map and sum of route sizes match
18204  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18205  {
18206  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18207  }
18208  if(SizeVal != Route2MultiMap.size())
18209  {
18210  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18211  (AnsiString)Caller);
18212  }
18213  Utilities->CallLogPop(404);
18214  return;
18215 }
18216 
18217 // ---------------------------------------------------------------------------
18218 
18219 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18220 /*
18221  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18222  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18223  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18224 */
18225 {
18226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18227  if(!Route2MultiMap.empty())
18228  {
18229  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18230  {
18231  if(Route2MultiMapIterator->second.first > RouteNumber)
18232  {
18233  Route2MultiMapIterator->second.first--;
18234  }
18235  }
18236  }
18237  Utilities->CallLogPop(405);
18238 }
18239 
18240 // ---------------------------------------------------------------------------
18241 
18242 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18243 /*
18244  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18245  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18246  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18247 */
18248 {
18249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18250  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18251  if(!Route2MultiMap.empty())
18252  {
18253  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18254  {
18255  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18256  {
18257  Route2MultiMapIterator->second.second--;
18258  }
18259  }
18260  }
18261  Utilities->CallLogPop(406);
18262 }
18263 
18264 // ---------------------------------------------------------------------------
18265 
18266 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18267 /*
18268  Erases the route element from Route2MultiMap and from the PrefDirVector.
18269  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18270  decremented if they are greater than the element number removed, and if the entire route is removed
18271  then the route numbers are also decremented in the map for route numbers that are greater than the route
18272  number that is removed.
18273 */
18274 {
18275  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18276  AnsiString(ELink));
18277  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18278  TRoute2MultiMapIterator Route2MultiMapIterator;
18279 
18280  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18281  if(RequiredRoutePair.first == -1)
18282  {
18283  throw Exception("Failed to find route element in RemoveRouteElement");
18284  }
18285  Route2MultiMap.erase(Route2MultiMapIterator);
18286  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18287 
18288 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18289  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18290 
18291  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18292  {
18293  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18294  }
18295 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18296 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18297 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18298 // to check if a route element is present, and the element has already been removed from the map - see above.
18299 
18300 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18301 /*
18302  int LockedVectorNumber = -1;
18303  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18304  {
18305  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18306  }
18307 */
18308 
18309 // erase element from route
18310  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18311  RequiredRoutePair.second)));
18312 // CheckMapAndRoutes();//test - drop - tested below
18313 
18314 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18315 // be so as continuation exit is at the end of the route, and truncation is from the end
18317  {
18319  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18320  AutoSigVectorIT--)
18321  {
18322  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18323  {
18324  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18325  }
18326  }
18327  }
18328 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18329 // and adjust all the corresponding route numbers
18330  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18331  {
18332  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18333  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18334  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18335 
18336 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18337  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18338  it is erased then - see TInterface::ApproachLocking
18339 
18340  if(LockedVectorNumber > -1)
18341  {
18342  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18343  }
18344 */
18345  // decrement route numbers in the locked route vector whether or not this route is a locked route
18346  if(!LockedRouteVector.empty())
18347  {
18348  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18349  {
18350  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18351  {
18352  LRVIT->RouteNumber--;
18353  }
18354  }
18355  }
18357  {
18359  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18360  AutoSigVectorIT--)
18361  {
18362  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18363  {
18364  AutoSigVectorIT->RouteNumber--;
18365  }
18366  }
18367  }
18368  }
18369  CheckMapAndRoutes(7); // test
18370  Utilities->CallLogPop(407);
18371 }
18372 
18373 // ---------------------------------------------------------------------------
18374 
18375 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18376 /*
18377  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18378  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18379  since that catches all route elements wherever created
18380 */
18381 {
18382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18383  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18384  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18385  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18386  Utilities->CallLogPop(408);
18387 }
18388 
18389 // ---------------------------------------------------------------------------
18390 
18391 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18392 /*
18393  Enter with signal at TrackVectorElement already set to red by the passing train.
18394  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18395  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18396  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18397  case the function sets no further signals.
18398 */
18399 {
18400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18401  "," + AnsiString(XLinkPos));
18402  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18403  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18404 
18405  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18406  if(RouteElementPair.first == -1)
18407  {
18408  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18409  }
18410  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18411 
18412  RequiredPair = RouteElementPair;
18413  if(RouteElement.XLinkPos != XLinkPos)
18414  {
18415  if(SecondPair.first != -1)
18416  {
18417  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18418  RequiredPair = SecondPair;
18419  if(RouteElement.XLinkPos != XLinkPos)
18420  {
18421  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18422  }
18423  }
18424  else
18425  {
18426  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18427  }
18428  }
18429 // new function
18430  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18431  Utilities->CallLogPop(409);
18432 }
18433 
18434 // ---------------------------------------------------------------------------
18435 
18436 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18437 /*
18438  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18439  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18440  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18441  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18442  to 2 for successive calls.
18443  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18444  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18445  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18446  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18447 */
18448 {
18449  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18450  AnsiString(AccessNumber));
18451  TPrefDirElement RouteElement;
18452  int Attribute = AccessNumber + 1;
18453 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18454  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18455 
18456  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18457  {
18458  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18459  }
18460  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18461  {
18462  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18463  }
18464  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18465  x).XLinkPos] != End)
18466  {
18467  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18468  }
18469 // new function
18470  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18471  Utilities->CallLogPop(410);
18472 }
18473 
18474 // ---------------------------------------------------------------------------
18475 
18476 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18477 /*
18478  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18479  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18480  or (b) in a linked rear route, in which case the function sets no further signals.
18481 
18482  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18483  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18484  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18485  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18486  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18487  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18488  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18489  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18490  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18491  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18492  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18493  found behind the train.
18494 
18495  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18496  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18497  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18498  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18499  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18500  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18501  a route.
18502 
18503  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18504  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18505  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
18506  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
18507  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18508  reference. If no train is found before the beginning of the route is reached the function returns true
18509 
18510 */
18511 {
18512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18513  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18514  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18515  int RearwardLinkedRouteNumber;
18516 
18517  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18518  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18519  // signal value in the route for use in further linked routes
18520  {
18521  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18522  {
18523  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18524  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18525  {
18526  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18527  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18528  {
18529  break;
18530  }
18531  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18532  // flash LCs on those routes
18533  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18534  }
18535  }
18536  }
18537  else
18538  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18539  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18540  {
18541  int TrainID, TrainPosition, BehindTrainPosition;
18542  bool FoundTrain = false, BehindTrain = false;
18543  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18544  {
18545  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18546  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18547  TrainID = TrackElement.TrainIDOnElement;
18548  if(TrackElement.TrackType == Bridge)
18549  {
18550  if(PrefDirElement.XLinkPos < 2)
18551  {
18552  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18553  }
18554  else
18555  {
18556  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18557  }
18558  }
18559  if(TrainID == -1)
18560  {
18561  continue;
18562  }
18563  else
18564  {
18565  FoundTrain = true;
18566  TrainPosition = x;
18567  break;
18568  }
18569  }
18570  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18571  {
18572  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18573  {
18574  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18575  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18576  // need the element behind the rearmost train.
18577  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18578  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18579  TrainID = TrackElement.TrainIDOnElement;
18580  if(TrackElement.TrackType == Bridge)
18581  {
18582  if(PrefDirElement.XLinkPos < 2)
18583  {
18584  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18585  }
18586  else
18587  {
18588  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18589  }
18590  }
18591  if(TrainID != -1)
18592  {
18593  continue; // still on train
18594  }
18595  else
18596  {
18597  BehindTrain = true;
18598  BehindTrainPosition = x;
18599  break;
18600  }
18601  }
18602  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18603  // so on for as many trains as there are on the single route
18604  {
18605  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18606  // first signal behind train to be red
18607  }
18608  }
18609  }
18610  Utilities->CallLogPop(411);
18611 }
18612 
18613 // ---------------------------------------------------------------------------
18614 
18615 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18616 {
18617 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18618  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18619  first signal is red, then OK
18620 */
18621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18622  AnsiString(RouteTruncatePosition));
18623  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18624  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18625  TPrefDirElement PrefDirElement, FirstElement;
18626  TTrackElement TrackElement;
18627  bool ExamineRoute = true;
18628 
18629  while(ExamineRoute)
18630  {
18631  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18632  {
18633  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18634  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18635  TrainID = TrackElement.TrainIDOnElement;
18636  if(TrackElement.TrackType == Bridge)
18637  {
18638  if(PrefDirElement.XLinkPos < 2)
18639  {
18640  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18641  }
18642  else
18643  {
18644  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18645  }
18646  }
18647  if(TrainID > -1)
18648  {
18649  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18650  {
18651  //any trains further back in route will be protected by the red signal behind the stopped train
18652  Utilities->CallLogPop(412);
18653  return(false);
18654  }
18655  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18656  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18657  //other way & can cancel the route
18658  {
18659  Utilities->CallLogPop(2203);
18660  return(false);
18661  }
18662  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18663  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18664  }
18665  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18666  {
18667  if(TrackElement.Attribute == 0)
18668  {
18669  Utilities->CallLogPop(413);
18670  return(false); // OK, red signal in front of a train
18671  }
18672  SignalCount++;
18673  if(SignalCount >= 3)
18674  {
18675  Utilities->CallLogPop(414);
18676  return(false);
18677  }
18678  }
18679  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18680  // ElinkPos because working back along PrefDir to beginning
18681  {
18682  Utilities->CallLogPop(415);
18683  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18684  }
18685  }
18686  //now look at linked rearwards routes
18687  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18688  StartPosition = CurrentRoute.PrefDirSize() - 1;
18689  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18690  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18691  {
18692  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18693  ExamineRoute = true;
18694  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18695  }
18696  else
18697  {
18698  // here check for a train on the element immediately before the first route element
18699  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18700  TrainID = PriorTrackElement.TrainIDOnElement;
18701  if(PriorTrackElement.TrackType == Bridge)
18702  {
18703  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18704  {
18705  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18706  }
18707  else
18708  {
18709  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18710  }
18711  }
18712  if(TrainID > -1)
18713  {
18714  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18715  {
18716  Utilities->CallLogPop(748);
18717  return(false);
18718  }
18719  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18720  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18721  //other way & can cancel the route
18722  {
18723  Utilities->CallLogPop(2204);
18724  return(false);
18725  }
18726  Utilities->CallLogPop(1962);
18727  return(true); //otherwise need to lock the route
18728  }
18729  ExamineRoute = false;
18730  }
18731  }
18732 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18733 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18734  Utilities->CallLogPop(416);
18735  return(false);
18736 }
18737 
18738 // ---------------------------------------------------------------------------
18739 
18740 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18741  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18742 {
18743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18744  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18745  TPrefDirElement InternalPrefDirElement; // blank element
18746 
18747  PrefDirElement = InternalPrefDirElement;
18748  if(LockedRouteVector.empty())
18749  {
18750  Utilities->CallLogPop(417);
18751  return(false);
18752  }
18753 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18754 // even if some elements have been removed from the front by a train
18755  bool InLockedRoute = false;
18756 
18757  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18758  {
18759  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18760  {
18761  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18762  // doesn't arise)
18763  InLockedRoute = true;
18764  break;
18765  }
18766  }
18767  if(!InLockedRoute)
18768  {
18769  Utilities->CallLogPop(418);
18770  return(false);
18771  }
18772  int RouteNumber, VectorCount = 0;
18773  TRouteType RouteType;
18774 
18775  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18776  {
18777  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18778  if(RouteType == NoRoute)
18779  {
18780  continue;
18781  }
18782  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18783  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18784  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18785  {
18786  throw Exception
18787  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18788  }
18789  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18790  {
18791  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18792  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18793  {
18794  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18795  {
18796  PrefDirElement = InternalPrefDirElement;
18797  LockedVectorNumber = VectorCount;
18798  Utilities->CallLogPop(419);
18799  return(true);
18800  }
18801  }
18802  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18803  {
18804  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18805  {
18806  PrefDirElement = InternalPrefDirElement;
18807  LockedVectorNumber = VectorCount;
18808  Utilities->CallLogPop(420);
18809  return(true);
18810  }
18811  else
18812  {
18813  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18814  }
18815  }
18816  }
18817  VectorCount++;
18818  }
18819  Utilities->CallLogPop(421);
18820  return(false);
18821 }
18822 
18823 // ---------------------------------------------------------------------------
18824 
18826 {
18827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
18828  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18829  {
18830  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
18831  {
18832  Utilities->CallLogPop(963);
18833  return(x);
18834  }
18835  }
18836  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
18837 }
18838 
18839 // ---------------------------------------------------------------------------
18840 
18842 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
18843 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
18844 {
18845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18846  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18847  {
18848  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
18849  {
18850  Utilities->CallLogPop(2039);
18851  return(true);
18852  }
18853  }
18854  Utilities->CallLogPop(2040);
18855  return(false);
18856 }
18857 
18858 // ---------------------------------------------------------------------------
18859 
18861 {
18862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18863  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18864  {
18865  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
18866  {
18867  Utilities->CallLogPop(964);
18868  return(GetFixedRouteAt(159, x));
18869  }
18870  }
18871  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18872 }
18873 
18874 // ---------------------------------------------------------------------------
18875 
18877 {
18878  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
18879  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18880  {
18881  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
18882  {
18883  Utilities->CallLogPop(965);
18884  return(GetModifiableRouteAt(15, x));
18885  }
18886  }
18887  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18888 }
18889 
18890 // ---------------------------------------------------------------------------
18891 
18892 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
18893 {
18894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
18895  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
18896  Utilities->SaveFileInt(OutFile, NextRouteID);
18897  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18898  {
18899  TOneRoute OneRoute = GetFixedRouteAt(165, x);
18900  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
18901  OneRoute.SavePrefDirVector(6, OutFile);
18902  }
18903  Utilities->CallLogPop(1442);
18904 }
18905 
18906 // ---------------------------------------------------------------------------
18907 
18908 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
18909 {
18910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
18911  int NumberOfRoutes;
18912 
18913  NumberOfRoutes = Utilities->LoadFileInt(InFile);
18914  NextRouteID = Utilities->LoadFileInt(InFile);
18915  for(int x = 0; x < NumberOfRoutes; x++)
18916  {
18917  TOneRoute OneRoute; // empty route
18918  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
18919  OneRoute.LoadPrefDir(2, InFile);
18921  {
18922  StoreOneRouteAfterSessionLoad(0, &OneRoute);
18923  }
18924  else
18925  {
18926  Utilities->CallLogPop(1443);
18927  return(false);
18928  }
18929  }
18930  Utilities->CallLogPop(1444);
18931  return(true);
18932 }
18933 
18934 // ---------------------------------------------------------------------------
18935 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
18936 {
18937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
18938  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
18939 
18940  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
18941  {
18942  Utilities->CallLogPop(1445);
18943  return(false);
18944  }
18945  int NextID = Utilities->LoadFileInt(InFile);
18946 
18947  if((NextID < 0) || (NextID > 1000000))
18948  {
18949  Utilities->CallLogPop(1446);
18950  return(false);
18951  }
18952  for(int x = 0; x < NumberOfRoutes; x++)
18953  {
18954  int RouteID = Utilities->LoadFileInt(InFile);
18955  if((RouteID < 0) || (RouteID > 20000))
18956  {
18957  Utilities->CallLogPop(1447);
18958  return(false);
18959  }
18960  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
18961  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
18962  {
18963  Utilities->CallLogPop(1448);
18964  return(false);
18965  }
18966  }
18967  Utilities->CallLogPop(1449);
18968  return(true);
18969 }
18970 
18971 // ---------------------------------------------------------------------------
18972 
18973 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
18974 {
18975  // return true for a loop
18976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
18977  AnsiString(StartPosition));
18978  if(EndPosition == StartPosition)
18979  {
18980  Utilities->CallLogPop(1839);
18981  return(true); // shouldn't happen but treat as a loop if does
18982  }
18983 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
18984  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
18985  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
18986 
18987  while(TrackIsInARoute(15, TVPos, LkPos))
18988  {
18989  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
18990  int NewLkPos = -1;
18991  if(NewTVPos > -1)
18992  {
18993  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
18994  if(NewLkPos == -1)
18995  {
18996  Utilities->CallLogPop(1840);
18997  return(true); // shouldn't arise but treat as loop if does
18998  }
18999  }
19000  else // reached a buffer or continuation
19001  {
19002  Utilities->CallLogPop(1841);
19003  return(false);
19004  }
19005 //Error found by Xeon notified by email 13/10/20.
19006 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19007 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19008 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19009 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19010 //New check added for v2.6.0
19011 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19012 //as possible in case there are other unforeseen effects.
19013  int RouteNumber; //dummy, not used
19014  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19015  {
19016  Utilities->CallLogPop(2241);
19017  return(false);
19018  }
19019  //now make the connected element the current element, read across the TV number and determine the exit link
19020  TVPos = NewTVPos;
19021  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19022  {
19023  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19024  {
19025  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19026  {
19027  LkPos = 1;
19028  }
19029  else
19030  {
19031  LkPos = 3;
19032  }
19033  }
19034  else
19035  {
19036  LkPos = 0;
19037  }
19038  }
19039  else
19040  {
19041  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19042  }
19043  if(TVPos == StartPosition)
19044  {
19045  Utilities->CallLogPop(1842);
19046  return(true); // it is a loop
19047  }
19048  }
19049  Utilities->CallLogPop(1843);
19050  return(false); // reached end of route so not a loop
19051 }
19052 
19053 // ---------------------------------------------------------------------------
19054 
19055 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19056 /*
19057  Track geometry allows diagonals to cross without occupying the same track element, so when
19058  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19059  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19060  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19061  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19062  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19063  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19064  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19065  Each of these is examined in turn for each route element in the relevant position.
19066 
19067  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19068  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19069  that returns false in all cases (including elements & links not present) except train present.
19070 */
19071 {
19072  int TrainID; // not used in this function
19073 
19074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19075  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19076  TPrefDirElement TempPrefDirElement;
19077  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19078 
19079  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19080  if(FirstPair.first > -1)
19081  {
19082  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19083  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19084  {
19085  Utilities->CallLogPop(310);
19086  return(true);
19087  }
19088  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19089  {
19090  Utilities->CallLogPop(311);
19091  return(true);
19092  }
19093  }
19094  if(SecondPair.first > -1)
19095  {
19096  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19097  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19098  {
19099  Utilities->CallLogPop(312);
19100  return(true);
19101  }
19102  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19103  {
19104  Utilities->CallLogPop(313);
19105  return(true);
19106  }
19107  }
19108  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19109  9, TrainID)))
19110  {
19111  Utilities->CallLogPop(1997);
19112  return(true);
19113  }
19114  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19115  if(FirstPair.first > -1)
19116  {
19117  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19118  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19119  {
19120  Utilities->CallLogPop(314);
19121  return(true);
19122  }
19123  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19124  {
19125  Utilities->CallLogPop(315);
19126  return(true);
19127  }
19128  }
19129  if(SecondPair.first > -1)
19130  {
19131  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19132  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19133  {
19134  Utilities->CallLogPop(316);
19135  return(true);
19136  }
19137  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19138  {
19139  Utilities->CallLogPop(317);
19140  return(true);
19141  }
19142  }
19143  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19144  9, TrainID)))
19145  {
19146  Utilities->CallLogPop(1998);
19147  return(true);
19148  }
19149  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19150  if(FirstPair.first > -1)
19151  {
19152  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19153  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19154  {
19155  Utilities->CallLogPop(318);
19156  return(true);
19157  }
19158  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19159  {
19160  Utilities->CallLogPop(319);
19161  return(true);
19162  }
19163  }
19164  if(SecondPair.first > -1)
19165  {
19166  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19167  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19168  {
19169  Utilities->CallLogPop(320);
19170  return(true);
19171  }
19172  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19173  {
19174  Utilities->CallLogPop(321);
19175  return(true);
19176  }
19177  }
19178  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19179  7, TrainID)))
19180  {
19181  Utilities->CallLogPop(1999);
19182  return(true);
19183  }
19184  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19185  if(FirstPair.first > -1)
19186  {
19187  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19188  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19189  {
19190  Utilities->CallLogPop(322);
19191  return(true);
19192  }
19193  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19194  {
19195  Utilities->CallLogPop(323);
19196  return(true);
19197  }
19198  }
19199  if(SecondPair.first > -1)
19200  {
19201  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19202  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19203  {
19204  Utilities->CallLogPop(324);
19205  return(true);
19206  }
19207  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19208  {
19209  Utilities->CallLogPop(325);
19210  return(true);
19211  }
19212  }
19213  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19214  3, TrainID)))
19215  {
19216  Utilities->CallLogPop(2000);
19217  return(true);
19218  }
19219  Utilities->CallLogPop(326);
19220  return(false);
19221 }
19222 
19223 // ---------------------------------------------------------------------------
19224 
19225 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19226 /*
19227  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19228  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19229  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19230  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19231  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19232  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19233  Each of these is examined in turn for each route element in the relevant position.
19234 */
19235 {
19236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19237  "," + AnsiString(DiagonalLinkNumber));
19238  TPrefDirElement TempPrefDirElement;
19239  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19240 
19241  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19242  if(FirstPair.first > -1)
19243  {
19244  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19245  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19246  {
19247  Utilities->CallLogPop(2010);
19248  return(true);
19249  }
19250  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19251  {
19252  Utilities->CallLogPop(2011);
19253  return(true);
19254  }
19255  }
19256  if(SecondPair.first > -1)
19257  {
19258  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19259  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19260  {
19261  Utilities->CallLogPop(2012);
19262  return(true);
19263  }
19264  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19265  {
19266  Utilities->CallLogPop(2013);
19267  return(true);
19268  }
19269  }
19270  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19271  if(FirstPair.first > -1)
19272  {
19273  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19274  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19275  {
19276  Utilities->CallLogPop(2014);
19277  return(true);
19278  }
19279  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19280  {
19281  Utilities->CallLogPop(2015);
19282  return(true);
19283  }
19284  }
19285  if(SecondPair.first > -1)
19286  {
19287  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19288  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19289  {
19290  Utilities->CallLogPop(2016);
19291  return(true);
19292  }
19293  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19294  {
19295  Utilities->CallLogPop(2017);
19296  return(true);
19297  }
19298  }
19299  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19300  if(FirstPair.first > -1)
19301  {
19302  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19303  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19304  {
19305  Utilities->CallLogPop(2018);
19306  return(true);
19307  }
19308  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19309  {
19310  Utilities->CallLogPop(2019);
19311  return(true);
19312  }
19313  }
19314  if(SecondPair.first > -1)
19315  {
19316  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19317  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19318  {
19319  Utilities->CallLogPop(2020);
19320  return(true);
19321  }
19322  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19323  {
19324  Utilities->CallLogPop(2021);
19325  return(true);
19326  }
19327  }
19328  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19329  if(FirstPair.first > -1)
19330  {
19331  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19332  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19333  {
19334  Utilities->CallLogPop(2022);
19335  return(true);
19336  }
19337  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19338  {
19339  Utilities->CallLogPop(2023);
19340  return(true);
19341  }
19342  }
19343  if(SecondPair.first > -1)
19344  {
19345  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19346  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19347  {
19348  Utilities->CallLogPop(2024);
19349  return(true);
19350  }
19351  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19352  {
19353  Utilities->CallLogPop(2025);
19354  return(true);
19355  }
19356  }
19357  Utilities->CallLogPop(2026);
19358  return(false);
19359 }
19360 
19361 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8341
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:677
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17470
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1294
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:917
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11241
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:663
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:730
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:613
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:565
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11214
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:450
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:584
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:875
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5381
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12760
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:772
TFixedTrackPiece
Definition: TrackUnit.h:84
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1700
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:802
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:908
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18066
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:93
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:791
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:909
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9806
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:793
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18476
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:920
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1348
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:794
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:581
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:702
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13181
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:759
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:620
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:809
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:448
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12800
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:679
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3625
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:700
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:881
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:792
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:299
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7061
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1617
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:16982
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:684
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1680
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:728
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5533
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6962
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5560
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1502
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:604
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1641
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:826
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:847
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1909
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:914
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10140
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:634
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16732
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:612
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:906
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19225
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:450
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1671
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:625
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2733
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:569
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5713
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:728
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:672
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7980
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1512
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:663
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:17904
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:763
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:596
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:666
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12539
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7447
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9407
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9184
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13829
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14892
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:566
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17430
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18266
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:857
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:855
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1621
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:873
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12343
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:159
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4355
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3571
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:673
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:831
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1524
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:582
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:760
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:796
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7795
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:456
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:662
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:585
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1026
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4515
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1308
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6245
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10625
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:654
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:868
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3447
Unused
@ Unused
Definition: TrackUnit.h:67
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:587
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:617
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1307
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:705
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18740
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2766
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:770
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:240
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:18935
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:592
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9351
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1679
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1522
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1608
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:222
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:918
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:676
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:454
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3171
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15415
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:777
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:669
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8247
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12605
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:796
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:794
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2782
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:730
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1006
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18014
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:775
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:819
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1375
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:706
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12856
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1715
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:595
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5673
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:670
TTrain
Definition: TrainUnit.h:279
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:394
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13700
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11255
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:561
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:588
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:644
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7462
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:67
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:790
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18375
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:856
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7208
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:921
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::Raising
@ Raising
Definition: TrackUnit.h:625
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:628
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:586
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10245
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:584
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1526
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1490
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:698
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:649
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:598
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:798
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:761
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:715
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1384
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5905
End
@ End
Definition: TrackUnit.h:77
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1528
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:668
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:843
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:636
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8601
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:864
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:904
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:581
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10354
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1019
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:317
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:800
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:743
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:804
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:578
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:914
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:126
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:723
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:758
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3738
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:990
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:860
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:991
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:244
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:701
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9316
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1000
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17418
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:520
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:778
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1071
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1645
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:792
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:827
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7476
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:685
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6654
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:661
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:242
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:685
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8640
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:907
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:817
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17403
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:756
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:657
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:813
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:801
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:76
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13470
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13207
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:714
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:913
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:66
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4440
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1859
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:814
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:829
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:594
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:804
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:448
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:778
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:95
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:816
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:575
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:10828
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18219
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4674
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:159
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1878
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:674
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:789
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:925
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:757
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:576
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:586
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:720
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:835
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:444
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:670
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11073
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:18841
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:604
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1017
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:611
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2750
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:710
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1534
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7433
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14646
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7089
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8437
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7168
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:667
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:721
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5584
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:707
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:292
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:698
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1310
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:860
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:803
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:802
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12944
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:766
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:867
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12079
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1646
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1698
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:47
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:905
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:588
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12572
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:652
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17190
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3548
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13160
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11116
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10491
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1761
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:764
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:925
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:595
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5767
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12392
Under
@ Under
Definition: TrackUnit.h:77
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16700
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:813
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:696
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:640
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2805
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11267
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11587
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:871
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:445
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:136
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10389
Lead
@ Lead
Definition: TrackUnit.h:77
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5632
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1795
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13408
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:879
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:554
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3764
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5424
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6226
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:87
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1339
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9112
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:579
TTrack::Up
@ Up
Definition: TrackUnit.h:625
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:863
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:815
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:599
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10368
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:924
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1484
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8404
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1639
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:755
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:218
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17257
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1628
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:781
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6112
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:817
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:623
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8350
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:783
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7117
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9779
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:77
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:586
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:604
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:785
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17707
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:154
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1529
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12442
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11012
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4524
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:584
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10340
TGraphicElement::Width
int Width
Definition: TrackUnit.h:452
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18615
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:18825
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17533
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:790
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:742
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:570
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:636
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:4065
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:771
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14238
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:672
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4043
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2340
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:705
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9252
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12210
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:589
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:862
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:952
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5608
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18908
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:568
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1526
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:911
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:769
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1515
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:828
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6815
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:759
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1030
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1032
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7648
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17349
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:673
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7190
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:785
Erase
@ Erase
Definition: TrackUnit.h:68
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:832
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5229
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:813
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1678
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:812
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:859
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:576
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13230
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:632
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:10924
Parapet
@ Parapet
Definition: TrackUnit.h:68
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17376
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:786
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:994
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:287
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8921
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17322
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:852
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:813
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18242
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:591
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:916
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:788
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:784
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:807
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1035
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:738
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:799
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14491
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:824
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:138
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:220
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11144
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12137
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1288
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17285
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:597
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:732
TTrack
Definition: TrackUnit.h:562
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1347
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:860
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1378
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18391
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1615
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7949
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:621
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:602
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:841
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:651
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:727
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:850
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:129
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:806
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:686
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:218
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:17882
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:226
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8717
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:910
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6006
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2092
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:601
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:725
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:159
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:845
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:796
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2558
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:216
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1613
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7612
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11925
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12703
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:600
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1490
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10277
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8313
IDInt
Definition: TrackUnit.h:511
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2321
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:574
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:18876
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:598
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:779
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4328
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10027
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4974
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:814
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:773
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:822
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:454
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:18973
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1106
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9035
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:584
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:98
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7559
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1289
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:887
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13013
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:774
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:731
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:632
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:224
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:848
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14034
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1683
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:131
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:768
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7527
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:646
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:809
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:782
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:716
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:895
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:755
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1501
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:839
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1619
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:836
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1629
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4596
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:571
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:8861
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:655
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15221
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1317
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:717
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:448
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13336
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:813
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1295
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13111
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
Points
@ Points
Definition: TrackUnit.h:67
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:703
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:724
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:17955
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:854
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9710
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:10995
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:583
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:821
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
Trail
@ Trail
Definition: TrackUnit.h:77
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17234
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9094
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16819
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:762
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1831
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:805
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16637
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:818
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:648
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:726
Continuation
@ Continuation
Definition: TrackUnit.h:67
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1026
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7406
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3648
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5844
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9141
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:853
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:861
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:869
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11968
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:590
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:823
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:753
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:858
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:448
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14682
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1015
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3265
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:452
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:874
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1518
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:689
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:622
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:740
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1677
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:912
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:281
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:729
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:837
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19055
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:12908
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1004
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:767
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1492
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1008
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:780
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:616
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:889
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4581
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:872
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:17853
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1710
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8451
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:699
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:709
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:577
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:800
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:653
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10782
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:811
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:720
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1349
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18892
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:594
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1841
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4566
Connection
@ Connection
Definition: TrackUnit.h:77
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3625
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1685
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9373
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:995
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:733
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16450
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11786
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:707
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:810
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8377
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:860
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1013
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18164
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18120
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6888
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10653
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:692
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:851
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:734
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1376
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:884
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5652
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:844
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:708
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:448
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:767
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9833
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:586
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:736
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:747
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17390
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4706
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:788
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2661
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:675
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7487
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3027
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:840
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:133
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:865
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16608
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:642
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13600
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:765
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:590
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:706
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:614
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1289
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:667
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:677
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:900
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:625
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11346
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:448
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:919
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:101
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1488
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:213
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8500
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:798
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1739
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8682
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:626
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:572
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:724
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13307
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:18860
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:624
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1346
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4188
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:806
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4457
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7350
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1936
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1021
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6152
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:992
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:695
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:825
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:627
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7145
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1378
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:226
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:679
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:870
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:771
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:651
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4482
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:782
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1623
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1028
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:765
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:922
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7900
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:665
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1302
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:795
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:830
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9290
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1002
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:754
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10889
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1746
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:815
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:624
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1490
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15642
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7333
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:808
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:780
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:678
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1492
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:629
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6169
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:709
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3525
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:757
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:643
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:597
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:787
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:753
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10815
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:774
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:866
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:834
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:693
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:913
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:279
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:694
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:638
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:713
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1054
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:567
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16016
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:700
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:811
RouteCall
@ RouteCall
Definition: TrackUnit.h:1295
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11280
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:846
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:592
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:77
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:683
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18436
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:241
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:593
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:580
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10844
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10109
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:688
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:532
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:216
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:776
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:915
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6070
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:159
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:923
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:745
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11292
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1351
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1511
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:838
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:722
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:808
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:693
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:586
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:615
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10100
Bridge
@ Bridge
Definition: TrackUnit.h:67
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:849
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1289
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:797
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:77
Buffers
@ Buffers
Definition: TrackUnit.h:67
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16366
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:690
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:77
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11304
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4394
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11227
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:833